162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * max98390.c -- MAX98390 ALSA Soc Audio driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2020 Maxim Integrated Products 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/acpi.h> 1062306a36Sopenharmony_ci#include <linux/cdev.h> 1162306a36Sopenharmony_ci#include <linux/dmi.h> 1262306a36Sopenharmony_ci#include <linux/firmware.h> 1362306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1462306a36Sopenharmony_ci#include <linux/i2c.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/of_gpio.h> 1762306a36Sopenharmony_ci#include <linux/regmap.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/time.h> 2062306a36Sopenharmony_ci#include <sound/pcm.h> 2162306a36Sopenharmony_ci#include <sound/pcm_params.h> 2262306a36Sopenharmony_ci#include <sound/soc.h> 2362306a36Sopenharmony_ci#include <sound/tlv.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "max98390.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic struct reg_default max98390_reg_defaults[] = { 2862306a36Sopenharmony_ci {MAX98390_INT_EN1, 0xf0}, 2962306a36Sopenharmony_ci {MAX98390_INT_EN2, 0x00}, 3062306a36Sopenharmony_ci {MAX98390_INT_EN3, 0x00}, 3162306a36Sopenharmony_ci {MAX98390_INT_FLAG_CLR1, 0x00}, 3262306a36Sopenharmony_ci {MAX98390_INT_FLAG_CLR2, 0x00}, 3362306a36Sopenharmony_ci {MAX98390_INT_FLAG_CLR3, 0x00}, 3462306a36Sopenharmony_ci {MAX98390_IRQ_CTRL, 0x01}, 3562306a36Sopenharmony_ci {MAX98390_CLK_MON, 0x6d}, 3662306a36Sopenharmony_ci {MAX98390_DAT_MON, 0x03}, 3762306a36Sopenharmony_ci {MAX98390_WDOG_CTRL, 0x00}, 3862306a36Sopenharmony_ci {MAX98390_WDOG_RST, 0x00}, 3962306a36Sopenharmony_ci {MAX98390_MEAS_ADC_THERM_WARN_THRESH, 0x75}, 4062306a36Sopenharmony_ci {MAX98390_MEAS_ADC_THERM_SHDN_THRESH, 0x8c}, 4162306a36Sopenharmony_ci {MAX98390_MEAS_ADC_THERM_HYSTERESIS, 0x08}, 4262306a36Sopenharmony_ci {MAX98390_PIN_CFG, 0x55}, 4362306a36Sopenharmony_ci {MAX98390_PCM_RX_EN_A, 0x00}, 4462306a36Sopenharmony_ci {MAX98390_PCM_RX_EN_B, 0x00}, 4562306a36Sopenharmony_ci {MAX98390_PCM_TX_EN_A, 0x00}, 4662306a36Sopenharmony_ci {MAX98390_PCM_TX_EN_B, 0x00}, 4762306a36Sopenharmony_ci {MAX98390_PCM_TX_HIZ_CTRL_A, 0xff}, 4862306a36Sopenharmony_ci {MAX98390_PCM_TX_HIZ_CTRL_B, 0xff}, 4962306a36Sopenharmony_ci {MAX98390_PCM_CH_SRC_1, 0x00}, 5062306a36Sopenharmony_ci {MAX98390_PCM_CH_SRC_2, 0x00}, 5162306a36Sopenharmony_ci {MAX98390_PCM_CH_SRC_3, 0x00}, 5262306a36Sopenharmony_ci {MAX98390_PCM_MODE_CFG, 0xc0}, 5362306a36Sopenharmony_ci {MAX98390_PCM_MASTER_MODE, 0x1c}, 5462306a36Sopenharmony_ci {MAX98390_PCM_CLK_SETUP, 0x44}, 5562306a36Sopenharmony_ci {MAX98390_PCM_SR_SETUP, 0x08}, 5662306a36Sopenharmony_ci {MAX98390_ICC_RX_EN_A, 0x00}, 5762306a36Sopenharmony_ci {MAX98390_ICC_RX_EN_B, 0x00}, 5862306a36Sopenharmony_ci {MAX98390_ICC_TX_EN_A, 0x00}, 5962306a36Sopenharmony_ci {MAX98390_ICC_TX_EN_B, 0x00}, 6062306a36Sopenharmony_ci {MAX98390_ICC_HIZ_MANUAL_MODE, 0x00}, 6162306a36Sopenharmony_ci {MAX98390_ICC_TX_HIZ_EN_A, 0x00}, 6262306a36Sopenharmony_ci {MAX98390_ICC_TX_HIZ_EN_B, 0x00}, 6362306a36Sopenharmony_ci {MAX98390_ICC_LNK_EN, 0x00}, 6462306a36Sopenharmony_ci {MAX98390_R2039_AMP_DSP_CFG, 0x0f}, 6562306a36Sopenharmony_ci {MAX98390_R203A_AMP_EN, 0x81}, 6662306a36Sopenharmony_ci {MAX98390_TONE_GEN_DC_CFG, 0x00}, 6762306a36Sopenharmony_ci {MAX98390_SPK_SRC_SEL, 0x00}, 6862306a36Sopenharmony_ci {MAX98390_SSM_CFG, 0x85}, 6962306a36Sopenharmony_ci {MAX98390_MEAS_EN, 0x03}, 7062306a36Sopenharmony_ci {MAX98390_MEAS_DSP_CFG, 0x0f}, 7162306a36Sopenharmony_ci {MAX98390_BOOST_CTRL0, 0x1c}, 7262306a36Sopenharmony_ci {MAX98390_BOOST_CTRL3, 0x01}, 7362306a36Sopenharmony_ci {MAX98390_BOOST_CTRL1, 0x40}, 7462306a36Sopenharmony_ci {MAX98390_MEAS_ADC_CFG, 0x07}, 7562306a36Sopenharmony_ci {MAX98390_MEAS_ADC_BASE_MSB, 0x00}, 7662306a36Sopenharmony_ci {MAX98390_MEAS_ADC_BASE_LSB, 0x23}, 7762306a36Sopenharmony_ci {MAX98390_ADC_CH0_DIVIDE, 0x00}, 7862306a36Sopenharmony_ci {MAX98390_ADC_CH1_DIVIDE, 0x00}, 7962306a36Sopenharmony_ci {MAX98390_ADC_CH2_DIVIDE, 0x00}, 8062306a36Sopenharmony_ci {MAX98390_ADC_CH0_FILT_CFG, 0x00}, 8162306a36Sopenharmony_ci {MAX98390_ADC_CH1_FILT_CFG, 0x00}, 8262306a36Sopenharmony_ci {MAX98390_ADC_CH2_FILT_CFG, 0x00}, 8362306a36Sopenharmony_ci {MAX98390_PWR_GATE_CTL, 0x2c}, 8462306a36Sopenharmony_ci {MAX98390_BROWNOUT_EN, 0x00}, 8562306a36Sopenharmony_ci {MAX98390_BROWNOUT_INFINITE_HOLD, 0x00}, 8662306a36Sopenharmony_ci {MAX98390_BROWNOUT_INFINITE_HOLD_CLR, 0x00}, 8762306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL_HOLD, 0x00}, 8862306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL1_THRESH, 0x00}, 8962306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL2_THRESH, 0x00}, 9062306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL3_THRESH, 0x00}, 9162306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL4_THRESH, 0x00}, 9262306a36Sopenharmony_ci {MAX98390_BROWNOUT_THRESH_HYSTERYSIS, 0x00}, 9362306a36Sopenharmony_ci {MAX98390_BROWNOUT_AMP_LIMITER_ATK_REL, 0x1f}, 9462306a36Sopenharmony_ci {MAX98390_BROWNOUT_AMP_GAIN_ATK_REL, 0x00}, 9562306a36Sopenharmony_ci {MAX98390_BROWNOUT_AMP1_CLIP_MODE, 0x00}, 9662306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL1_CUR_LIMIT, 0x00}, 9762306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL1_AMP1_CTRL1, 0x00}, 9862306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL1_AMP1_CTRL2, 0x00}, 9962306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL1_AMP1_CTRL3, 0x00}, 10062306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL2_CUR_LIMIT, 0x00}, 10162306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL2_AMP1_CTRL1, 0x00}, 10262306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL2_AMP1_CTRL2, 0x00}, 10362306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL2_AMP1_CTRL3, 0x00}, 10462306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL3_CUR_LIMIT, 0x00}, 10562306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL3_AMP1_CTRL1, 0x00}, 10662306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL3_AMP1_CTRL2, 0x00}, 10762306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL3_AMP1_CTRL3, 0x00}, 10862306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL4_CUR_LIMIT, 0x00}, 10962306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL4_AMP1_CTRL1, 0x00}, 11062306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL4_AMP1_CTRL2, 0x00}, 11162306a36Sopenharmony_ci {MAX98390_BROWNOUT_LVL4_AMP1_CTRL3, 0x00}, 11262306a36Sopenharmony_ci {MAX98390_BROWNOUT_ILIM_HLD, 0x00}, 11362306a36Sopenharmony_ci {MAX98390_BROWNOUT_LIM_HLD, 0x00}, 11462306a36Sopenharmony_ci {MAX98390_BROWNOUT_CLIP_HLD, 0x00}, 11562306a36Sopenharmony_ci {MAX98390_BROWNOUT_GAIN_HLD, 0x00}, 11662306a36Sopenharmony_ci {MAX98390_ENV_TRACK_VOUT_HEADROOM, 0x0f}, 11762306a36Sopenharmony_ci {MAX98390_ENV_TRACK_BOOST_VOUT_DELAY, 0x80}, 11862306a36Sopenharmony_ci {MAX98390_ENV_TRACK_REL_RATE, 0x07}, 11962306a36Sopenharmony_ci {MAX98390_ENV_TRACK_HOLD_RATE, 0x07}, 12062306a36Sopenharmony_ci {MAX98390_ENV_TRACK_CTRL, 0x01}, 12162306a36Sopenharmony_ci {MAX98390_BOOST_BYPASS1, 0x49}, 12262306a36Sopenharmony_ci {MAX98390_BOOST_BYPASS2, 0x2b}, 12362306a36Sopenharmony_ci {MAX98390_BOOST_BYPASS3, 0x08}, 12462306a36Sopenharmony_ci {MAX98390_FET_SCALING1, 0x00}, 12562306a36Sopenharmony_ci {MAX98390_FET_SCALING2, 0x03}, 12662306a36Sopenharmony_ci {MAX98390_FET_SCALING3, 0x00}, 12762306a36Sopenharmony_ci {MAX98390_FET_SCALING4, 0x07}, 12862306a36Sopenharmony_ci {MAX98390_SPK_SPEEDUP, 0x00}, 12962306a36Sopenharmony_ci {DSMIG_WB_DRC_RELEASE_TIME_1, 0x00}, 13062306a36Sopenharmony_ci {DSMIG_WB_DRC_RELEASE_TIME_2, 0x00}, 13162306a36Sopenharmony_ci {DSMIG_WB_DRC_ATTACK_TIME_1, 0x00}, 13262306a36Sopenharmony_ci {DSMIG_WB_DRC_ATTACK_TIME_2, 0x00}, 13362306a36Sopenharmony_ci {DSMIG_WB_DRC_COMPRESSION_RATIO, 0x00}, 13462306a36Sopenharmony_ci {DSMIG_WB_DRC_COMPRESSION_THRESHOLD, 0x00}, 13562306a36Sopenharmony_ci {DSMIG_WB_DRC_MAKEUPGAIN, 0x00}, 13662306a36Sopenharmony_ci {DSMIG_WB_DRC_NOISE_GATE_THRESHOLD, 0x00}, 13762306a36Sopenharmony_ci {DSMIG_WBDRC_HPF_ENABLE, 0x00}, 13862306a36Sopenharmony_ci {DSMIG_WB_DRC_TEST_SMOOTHER_OUT_EN, 0x00}, 13962306a36Sopenharmony_ci {DSMIG_PPR_THRESHOLD, 0x00}, 14062306a36Sopenharmony_ci {DSM_STEREO_BASS_CHANNEL_SELECT, 0x00}, 14162306a36Sopenharmony_ci {DSM_TPROT_THRESHOLD_BYTE0, 0x00}, 14262306a36Sopenharmony_ci {DSM_TPROT_THRESHOLD_BYTE1, 0x00}, 14362306a36Sopenharmony_ci {DSM_TPROT_ROOM_TEMPERATURE_BYTE0, 0x00}, 14462306a36Sopenharmony_ci {DSM_TPROT_ROOM_TEMPERATURE_BYTE1, 0x00}, 14562306a36Sopenharmony_ci {DSM_TPROT_RECIP_RDC_ROOM_BYTE0, 0x00}, 14662306a36Sopenharmony_ci {DSM_TPROT_RECIP_RDC_ROOM_BYTE1, 0x00}, 14762306a36Sopenharmony_ci {DSM_TPROT_RECIP_RDC_ROOM_BYTE2, 0x00}, 14862306a36Sopenharmony_ci {DSM_TPROT_RECIP_TCONST_BYTE0, 0x00}, 14962306a36Sopenharmony_ci {DSM_TPROT_RECIP_TCONST_BYTE1, 0x00}, 15062306a36Sopenharmony_ci {DSM_TPROT_RECIP_TCONST_BYTE2, 0x00}, 15162306a36Sopenharmony_ci {DSM_THERMAL_ATTENUATION_SETTINGS, 0x00}, 15262306a36Sopenharmony_ci {DSM_THERMAL_PILOT_TONE_ATTENUATION, 0x00}, 15362306a36Sopenharmony_ci {DSM_TPROT_PG_TEMP_THRESH_BYTE0, 0x00}, 15462306a36Sopenharmony_ci {DSM_TPROT_PG_TEMP_THRESH_BYTE1, 0x00}, 15562306a36Sopenharmony_ci {DSMIG_DEBUZZER_THRESHOLD, 0x00}, 15662306a36Sopenharmony_ci {DSMIG_DEBUZZER_ALPHA_COEF_TEST_ONLY, 0x08}, 15762306a36Sopenharmony_ci {DSM_VOL_ENA, 0x20}, 15862306a36Sopenharmony_ci {DSM_VOL_CTRL, 0xa0}, 15962306a36Sopenharmony_ci {DSMIG_EN, 0x00}, 16062306a36Sopenharmony_ci {MAX98390_R23E1_DSP_GLOBAL_EN, 0x00}, 16162306a36Sopenharmony_ci {MAX98390_R23FF_GLOBAL_EN, 0x00}, 16262306a36Sopenharmony_ci}; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic int max98390_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 16762306a36Sopenharmony_ci struct max98390_priv *max98390 = 16862306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 16962306a36Sopenharmony_ci unsigned int mode; 17062306a36Sopenharmony_ci unsigned int format; 17162306a36Sopenharmony_ci unsigned int invert = 0; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 17662306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBC_CFC: 17762306a36Sopenharmony_ci mode = MAX98390_PCM_MASTER_MODE_SLAVE; 17862306a36Sopenharmony_ci break; 17962306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBP_CFP: 18062306a36Sopenharmony_ci max98390->provider = true; 18162306a36Sopenharmony_ci mode = MAX98390_PCM_MASTER_MODE_MASTER; 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci default: 18462306a36Sopenharmony_ci dev_err(component->dev, "DAI clock mode unsupported\n"); 18562306a36Sopenharmony_ci return -EINVAL; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 18962306a36Sopenharmony_ci MAX98390_PCM_MASTER_MODE, 19062306a36Sopenharmony_ci MAX98390_PCM_MASTER_MODE_MASK, 19162306a36Sopenharmony_ci mode); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 19462306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 19762306a36Sopenharmony_ci invert = MAX98390_PCM_MODE_CFG_PCM_BCLKEDGE; 19862306a36Sopenharmony_ci break; 19962306a36Sopenharmony_ci default: 20062306a36Sopenharmony_ci dev_err(component->dev, "DAI invert mode unsupported\n"); 20162306a36Sopenharmony_ci return -EINVAL; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 20562306a36Sopenharmony_ci MAX98390_PCM_MODE_CFG, 20662306a36Sopenharmony_ci MAX98390_PCM_MODE_CFG_PCM_BCLKEDGE, 20762306a36Sopenharmony_ci invert); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* interface format */ 21062306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 21162306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 21262306a36Sopenharmony_ci format = MAX98390_PCM_FORMAT_I2S; 21362306a36Sopenharmony_ci break; 21462306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 21562306a36Sopenharmony_ci format = MAX98390_PCM_FORMAT_LJ; 21662306a36Sopenharmony_ci break; 21762306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 21862306a36Sopenharmony_ci format = MAX98390_PCM_FORMAT_TDM_MODE1; 21962306a36Sopenharmony_ci break; 22062306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 22162306a36Sopenharmony_ci format = MAX98390_PCM_FORMAT_TDM_MODE0; 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci default: 22462306a36Sopenharmony_ci return -EINVAL; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 22862306a36Sopenharmony_ci MAX98390_PCM_MODE_CFG, 22962306a36Sopenharmony_ci MAX98390_PCM_MODE_CFG_FORMAT_MASK, 23062306a36Sopenharmony_ci format << MAX98390_PCM_MODE_CFG_FORMAT_SHIFT); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return 0; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic int max98390_get_bclk_sel(int bclk) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci int i; 23862306a36Sopenharmony_ci /* BCLKs per LRCLK */ 23962306a36Sopenharmony_ci static int bclk_sel_table[] = { 24062306a36Sopenharmony_ci 32, 48, 64, 96, 128, 192, 256, 320, 384, 512, 24162306a36Sopenharmony_ci }; 24262306a36Sopenharmony_ci /* match BCLKs per LRCLK */ 24362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) { 24462306a36Sopenharmony_ci if (bclk_sel_table[i] == bclk) 24562306a36Sopenharmony_ci return i + 2; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci return 0; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic int max98390_set_clock(struct snd_soc_component *component, 25162306a36Sopenharmony_ci struct snd_pcm_hw_params *params) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct max98390_priv *max98390 = 25462306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 25562306a36Sopenharmony_ci /* codec MCLK rate in master mode */ 25662306a36Sopenharmony_ci static int rate_table[] = { 25762306a36Sopenharmony_ci 5644800, 6000000, 6144000, 6500000, 25862306a36Sopenharmony_ci 9600000, 11289600, 12000000, 12288000, 25962306a36Sopenharmony_ci 13000000, 19200000, 26062306a36Sopenharmony_ci }; 26162306a36Sopenharmony_ci /* BCLK/LRCLK ratio calculation */ 26262306a36Sopenharmony_ci int blr_clk_ratio = params_channels(params) 26362306a36Sopenharmony_ci * snd_pcm_format_width(params_format(params)); 26462306a36Sopenharmony_ci int value; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (max98390->provider) { 26762306a36Sopenharmony_ci int i; 26862306a36Sopenharmony_ci /* match rate to closest value */ 26962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rate_table); i++) { 27062306a36Sopenharmony_ci if (rate_table[i] >= max98390->sysclk) 27162306a36Sopenharmony_ci break; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci if (i == ARRAY_SIZE(rate_table)) { 27462306a36Sopenharmony_ci dev_err(component->dev, "failed to find proper clock rate.\n"); 27562306a36Sopenharmony_ci return -EINVAL; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 27962306a36Sopenharmony_ci MAX98390_PCM_MASTER_MODE, 28062306a36Sopenharmony_ci MAX98390_PCM_MASTER_MODE_MCLK_MASK, 28162306a36Sopenharmony_ci i << MAX98390_PCM_MASTER_MODE_MCLK_RATE_SHIFT); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (!max98390->tdm_mode) { 28562306a36Sopenharmony_ci /* BCLK configuration */ 28662306a36Sopenharmony_ci value = max98390_get_bclk_sel(blr_clk_ratio); 28762306a36Sopenharmony_ci if (!value) { 28862306a36Sopenharmony_ci dev_err(component->dev, "format unsupported %d\n", 28962306a36Sopenharmony_ci params_format(params)); 29062306a36Sopenharmony_ci return -EINVAL; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 29462306a36Sopenharmony_ci MAX98390_PCM_CLK_SETUP, 29562306a36Sopenharmony_ci MAX98390_PCM_CLK_SETUP_BSEL_MASK, 29662306a36Sopenharmony_ci value); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci return 0; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic int max98390_dai_hw_params(struct snd_pcm_substream *substream, 30262306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 30362306a36Sopenharmony_ci struct snd_soc_dai *dai) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct snd_soc_component *component = 30662306a36Sopenharmony_ci dai->component; 30762306a36Sopenharmony_ci struct max98390_priv *max98390 = 30862306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci unsigned int sampling_rate; 31162306a36Sopenharmony_ci unsigned int chan_sz; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* pcm mode configuration */ 31462306a36Sopenharmony_ci switch (snd_pcm_format_width(params_format(params))) { 31562306a36Sopenharmony_ci case 16: 31662306a36Sopenharmony_ci chan_sz = MAX98390_PCM_MODE_CFG_CHANSZ_16; 31762306a36Sopenharmony_ci break; 31862306a36Sopenharmony_ci case 24: 31962306a36Sopenharmony_ci chan_sz = MAX98390_PCM_MODE_CFG_CHANSZ_24; 32062306a36Sopenharmony_ci break; 32162306a36Sopenharmony_ci case 32: 32262306a36Sopenharmony_ci chan_sz = MAX98390_PCM_MODE_CFG_CHANSZ_32; 32362306a36Sopenharmony_ci break; 32462306a36Sopenharmony_ci default: 32562306a36Sopenharmony_ci dev_err(component->dev, "format unsupported %d\n", 32662306a36Sopenharmony_ci params_format(params)); 32762306a36Sopenharmony_ci goto err; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 33162306a36Sopenharmony_ci MAX98390_PCM_MODE_CFG, 33262306a36Sopenharmony_ci MAX98390_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci dev_dbg(component->dev, "format supported %d", 33562306a36Sopenharmony_ci params_format(params)); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* sampling rate configuration */ 33862306a36Sopenharmony_ci switch (params_rate(params)) { 33962306a36Sopenharmony_ci case 8000: 34062306a36Sopenharmony_ci sampling_rate = MAX98390_PCM_SR_SET1_SR_8000; 34162306a36Sopenharmony_ci break; 34262306a36Sopenharmony_ci case 11025: 34362306a36Sopenharmony_ci sampling_rate = MAX98390_PCM_SR_SET1_SR_11025; 34462306a36Sopenharmony_ci break; 34562306a36Sopenharmony_ci case 12000: 34662306a36Sopenharmony_ci sampling_rate = MAX98390_PCM_SR_SET1_SR_12000; 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci case 16000: 34962306a36Sopenharmony_ci sampling_rate = MAX98390_PCM_SR_SET1_SR_16000; 35062306a36Sopenharmony_ci break; 35162306a36Sopenharmony_ci case 22050: 35262306a36Sopenharmony_ci sampling_rate = MAX98390_PCM_SR_SET1_SR_22050; 35362306a36Sopenharmony_ci break; 35462306a36Sopenharmony_ci case 24000: 35562306a36Sopenharmony_ci sampling_rate = MAX98390_PCM_SR_SET1_SR_24000; 35662306a36Sopenharmony_ci break; 35762306a36Sopenharmony_ci case 32000: 35862306a36Sopenharmony_ci sampling_rate = MAX98390_PCM_SR_SET1_SR_32000; 35962306a36Sopenharmony_ci break; 36062306a36Sopenharmony_ci case 44100: 36162306a36Sopenharmony_ci sampling_rate = MAX98390_PCM_SR_SET1_SR_44100; 36262306a36Sopenharmony_ci break; 36362306a36Sopenharmony_ci case 48000: 36462306a36Sopenharmony_ci sampling_rate = MAX98390_PCM_SR_SET1_SR_48000; 36562306a36Sopenharmony_ci break; 36662306a36Sopenharmony_ci default: 36762306a36Sopenharmony_ci dev_err(component->dev, "rate %d not supported\n", 36862306a36Sopenharmony_ci params_rate(params)); 36962306a36Sopenharmony_ci goto err; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* set DAI_SR to correct LRCLK frequency */ 37362306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 37462306a36Sopenharmony_ci MAX98390_PCM_SR_SETUP, 37562306a36Sopenharmony_ci MAX98390_PCM_SR_SET1_SR_MASK, 37662306a36Sopenharmony_ci sampling_rate); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci return max98390_set_clock(component, params); 37962306a36Sopenharmony_cierr: 38062306a36Sopenharmony_ci return -EINVAL; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic int max98390_dai_tdm_slot(struct snd_soc_dai *dai, 38462306a36Sopenharmony_ci unsigned int tx_mask, unsigned int rx_mask, 38562306a36Sopenharmony_ci int slots, int slot_width) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 38862306a36Sopenharmony_ci struct max98390_priv *max98390 = 38962306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci int bsel; 39262306a36Sopenharmony_ci unsigned int chan_sz; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (!tx_mask && !rx_mask && !slots && !slot_width) 39562306a36Sopenharmony_ci max98390->tdm_mode = false; 39662306a36Sopenharmony_ci else 39762306a36Sopenharmony_ci max98390->tdm_mode = true; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci dev_dbg(component->dev, 40062306a36Sopenharmony_ci "Tdm mode : %d\n", max98390->tdm_mode); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* BCLK configuration */ 40362306a36Sopenharmony_ci bsel = max98390_get_bclk_sel(slots * slot_width); 40462306a36Sopenharmony_ci if (!bsel) { 40562306a36Sopenharmony_ci dev_err(component->dev, "BCLK %d not supported\n", 40662306a36Sopenharmony_ci slots * slot_width); 40762306a36Sopenharmony_ci return -EINVAL; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 41162306a36Sopenharmony_ci MAX98390_PCM_CLK_SETUP, 41262306a36Sopenharmony_ci MAX98390_PCM_CLK_SETUP_BSEL_MASK, 41362306a36Sopenharmony_ci bsel); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* Channel size configuration */ 41662306a36Sopenharmony_ci switch (slot_width) { 41762306a36Sopenharmony_ci case 16: 41862306a36Sopenharmony_ci chan_sz = MAX98390_PCM_MODE_CFG_CHANSZ_16; 41962306a36Sopenharmony_ci break; 42062306a36Sopenharmony_ci case 24: 42162306a36Sopenharmony_ci chan_sz = MAX98390_PCM_MODE_CFG_CHANSZ_24; 42262306a36Sopenharmony_ci break; 42362306a36Sopenharmony_ci case 32: 42462306a36Sopenharmony_ci chan_sz = MAX98390_PCM_MODE_CFG_CHANSZ_32; 42562306a36Sopenharmony_ci break; 42662306a36Sopenharmony_ci default: 42762306a36Sopenharmony_ci dev_err(component->dev, "format unsupported %d\n", 42862306a36Sopenharmony_ci slot_width); 42962306a36Sopenharmony_ci return -EINVAL; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 43362306a36Sopenharmony_ci MAX98390_PCM_MODE_CFG, 43462306a36Sopenharmony_ci MAX98390_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci /* Rx slot configuration */ 43762306a36Sopenharmony_ci regmap_write(max98390->regmap, 43862306a36Sopenharmony_ci MAX98390_PCM_RX_EN_A, 43962306a36Sopenharmony_ci rx_mask & 0xFF); 44062306a36Sopenharmony_ci regmap_write(max98390->regmap, 44162306a36Sopenharmony_ci MAX98390_PCM_RX_EN_B, 44262306a36Sopenharmony_ci (rx_mask & 0xFF00) >> 8); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci /* Tx slot Hi-Z configuration */ 44562306a36Sopenharmony_ci regmap_write(max98390->regmap, 44662306a36Sopenharmony_ci MAX98390_PCM_TX_HIZ_CTRL_A, 44762306a36Sopenharmony_ci ~tx_mask & 0xFF); 44862306a36Sopenharmony_ci regmap_write(max98390->regmap, 44962306a36Sopenharmony_ci MAX98390_PCM_TX_HIZ_CTRL_B, 45062306a36Sopenharmony_ci (~tx_mask & 0xFF00) >> 8); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci return 0; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic int max98390_dai_set_sysclk(struct snd_soc_dai *dai, 45662306a36Sopenharmony_ci int clk_id, unsigned int freq, int dir) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 45962306a36Sopenharmony_ci struct max98390_priv *max98390 = 46062306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci max98390->sysclk = freq; 46362306a36Sopenharmony_ci return 0; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic const struct snd_soc_dai_ops max98390_dai_ops = { 46762306a36Sopenharmony_ci .set_sysclk = max98390_dai_set_sysclk, 46862306a36Sopenharmony_ci .set_fmt = max98390_dai_set_fmt, 46962306a36Sopenharmony_ci .hw_params = max98390_dai_hw_params, 47062306a36Sopenharmony_ci .set_tdm_slot = max98390_dai_tdm_slot, 47162306a36Sopenharmony_ci}; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic int max98390_dac_event(struct snd_soc_dapm_widget *w, 47462306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct snd_soc_component *component = 47762306a36Sopenharmony_ci snd_soc_dapm_to_component(w->dapm); 47862306a36Sopenharmony_ci struct max98390_priv *max98390 = 47962306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci switch (event) { 48262306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 48362306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 48462306a36Sopenharmony_ci MAX98390_R203A_AMP_EN, 48562306a36Sopenharmony_ci MAX98390_AMP_EN_MASK, 1); 48662306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 48762306a36Sopenharmony_ci MAX98390_R23FF_GLOBAL_EN, 48862306a36Sopenharmony_ci MAX98390_GLOBAL_EN_MASK, 1); 48962306a36Sopenharmony_ci break; 49062306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMD: 49162306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 49262306a36Sopenharmony_ci MAX98390_R23FF_GLOBAL_EN, 49362306a36Sopenharmony_ci MAX98390_GLOBAL_EN_MASK, 0); 49462306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 49562306a36Sopenharmony_ci MAX98390_R203A_AMP_EN, 49662306a36Sopenharmony_ci MAX98390_AMP_EN_MASK, 0); 49762306a36Sopenharmony_ci break; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci return 0; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic const char * const max98390_switch_text[] = { 50362306a36Sopenharmony_ci "Left", "Right", "LeftRight"}; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_cistatic const char * const max98390_boost_voltage_text[] = { 50662306a36Sopenharmony_ci "6.5V", "6.625V", "6.75V", "6.875V", "7V", "7.125V", "7.25V", "7.375V", 50762306a36Sopenharmony_ci "7.5V", "7.625V", "7.75V", "7.875V", "8V", "8.125V", "8.25V", "8.375V", 50862306a36Sopenharmony_ci "8.5V", "8.625V", "8.75V", "8.875V", "9V", "9.125V", "9.25V", "9.375V", 50962306a36Sopenharmony_ci "9.5V", "9.625V", "9.75V", "9.875V", "10V" 51062306a36Sopenharmony_ci}; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(max98390_boost_voltage, 51362306a36Sopenharmony_ci MAX98390_BOOST_CTRL0, 0, 51462306a36Sopenharmony_ci max98390_boost_voltage_text); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(max98390_spk_tlv, 300, 300, 0); 51762306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(max98390_digital_tlv, -8000, 50, 0); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic const char * const max98390_current_limit_text[] = { 52062306a36Sopenharmony_ci "0.00A", "0.50A", "1.00A", "1.05A", "1.10A", "1.15A", "1.20A", "1.25A", 52162306a36Sopenharmony_ci "1.30A", "1.35A", "1.40A", "1.45A", "1.50A", "1.55A", "1.60A", "1.65A", 52262306a36Sopenharmony_ci "1.70A", "1.75A", "1.80A", "1.85A", "1.90A", "1.95A", "2.00A", "2.05A", 52362306a36Sopenharmony_ci "2.10A", "2.15A", "2.20A", "2.25A", "2.30A", "2.35A", "2.40A", "2.45A", 52462306a36Sopenharmony_ci "2.50A", "2.55A", "2.60A", "2.65A", "2.70A", "2.75A", "2.80A", "2.85A", 52562306a36Sopenharmony_ci "2.90A", "2.95A", "3.00A", "3.05A", "3.10A", "3.15A", "3.20A", "3.25A", 52662306a36Sopenharmony_ci "3.30A", "3.35A", "3.40A", "3.45A", "3.50A", "3.55A", "3.60A", "3.65A", 52762306a36Sopenharmony_ci "3.70A", "3.75A", "3.80A", "3.85A", "3.90A", "3.95A", "4.00A", "4.05A", 52862306a36Sopenharmony_ci "4.10A" 52962306a36Sopenharmony_ci}; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(max98390_current_limit, 53262306a36Sopenharmony_ci MAX98390_BOOST_CTRL1, 0, 53362306a36Sopenharmony_ci max98390_current_limit_text); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic int max98390_ref_rdc_put(struct snd_kcontrol *kcontrol, 53662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci struct snd_soc_component *component = 53962306a36Sopenharmony_ci snd_soc_kcontrol_component(kcontrol); 54062306a36Sopenharmony_ci struct max98390_priv *max98390 = 54162306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci max98390->ref_rdc_value = ucontrol->value.integer.value[0]; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_RECIP_RDC_ROOM_BYTE0, 54662306a36Sopenharmony_ci max98390->ref_rdc_value & 0x000000ff); 54762306a36Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_RECIP_RDC_ROOM_BYTE1, 54862306a36Sopenharmony_ci (max98390->ref_rdc_value >> 8) & 0x000000ff); 54962306a36Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_RECIP_RDC_ROOM_BYTE2, 55062306a36Sopenharmony_ci (max98390->ref_rdc_value >> 16) & 0x000000ff); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci return 0; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic int max98390_ref_rdc_get(struct snd_kcontrol *kcontrol, 55662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci struct snd_soc_component *component = 55962306a36Sopenharmony_ci snd_soc_kcontrol_component(kcontrol); 56062306a36Sopenharmony_ci struct max98390_priv *max98390 = 56162306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci ucontrol->value.integer.value[0] = max98390->ref_rdc_value; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci return 0; 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistatic int max98390_ambient_temp_put(struct snd_kcontrol *kcontrol, 56962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 57062306a36Sopenharmony_ci{ 57162306a36Sopenharmony_ci struct snd_soc_component *component = 57262306a36Sopenharmony_ci snd_soc_kcontrol_component(kcontrol); 57362306a36Sopenharmony_ci struct max98390_priv *max98390 = 57462306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci max98390->ambient_temp_value = ucontrol->value.integer.value[0]; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_ROOM_TEMPERATURE_BYTE1, 57962306a36Sopenharmony_ci (max98390->ambient_temp_value >> 8) & 0x000000ff); 58062306a36Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_ROOM_TEMPERATURE_BYTE0, 58162306a36Sopenharmony_ci (max98390->ambient_temp_value) & 0x000000ff); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci return 0; 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic int max98390_ambient_temp_get(struct snd_kcontrol *kcontrol, 58762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci struct snd_soc_component *component = 59062306a36Sopenharmony_ci snd_soc_kcontrol_component(kcontrol); 59162306a36Sopenharmony_ci struct max98390_priv *max98390 = 59262306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci ucontrol->value.integer.value[0] = max98390->ambient_temp_value; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci return 0; 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic int max98390_adaptive_rdc_put(struct snd_kcontrol *kcontrol, 60062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci struct snd_soc_component *component = 60362306a36Sopenharmony_ci snd_soc_kcontrol_component(kcontrol); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci dev_warn(component->dev, "Put adaptive rdc not supported\n"); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci return 0; 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic int max98390_adaptive_rdc_get(struct snd_kcontrol *kcontrol, 61162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci int rdc, rdc0; 61462306a36Sopenharmony_ci struct snd_soc_component *component = 61562306a36Sopenharmony_ci snd_soc_kcontrol_component(kcontrol); 61662306a36Sopenharmony_ci struct max98390_priv *max98390 = 61762306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE1, &rdc); 62062306a36Sopenharmony_ci regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE0, &rdc0); 62162306a36Sopenharmony_ci ucontrol->value.integer.value[0] = rdc0 | rdc << 8; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci return 0; 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic int max98390_dsm_calib_get(struct snd_kcontrol *kcontrol, 62762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci /* Do nothing */ 63062306a36Sopenharmony_ci return 0; 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic int max98390_dsm_calib_put(struct snd_kcontrol *kcontrol, 63462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 63762306a36Sopenharmony_ci struct max98390_priv *max98390 = snd_soc_component_get_drvdata(component); 63862306a36Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 63962306a36Sopenharmony_ci unsigned int rdc, rdc_cal_result, rdc_integer, rdc_factor, temp, val; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci snd_soc_dapm_mutex_lock(dapm); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci regmap_read(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, &val); 64462306a36Sopenharmony_ci if (!val) { 64562306a36Sopenharmony_ci /* Enable the codec for the duration of calibration readout */ 64662306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, MAX98390_R203A_AMP_EN, 64762306a36Sopenharmony_ci MAX98390_AMP_EN_MASK, 1); 64862306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, 64962306a36Sopenharmony_ci MAX98390_GLOBAL_EN_MASK, 1); 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE1, &rdc); 65362306a36Sopenharmony_ci regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE0, &rdc_cal_result); 65462306a36Sopenharmony_ci regmap_read(max98390->regmap, MAX98390_MEAS_ADC_CH2_READ, &temp); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if (!val) { 65762306a36Sopenharmony_ci /* Disable the codec if it was disabled */ 65862306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, 65962306a36Sopenharmony_ci MAX98390_GLOBAL_EN_MASK, 0); 66062306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, MAX98390_R203A_AMP_EN, 66162306a36Sopenharmony_ci MAX98390_AMP_EN_MASK, 0); 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci snd_soc_dapm_mutex_unlock(dapm); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci rdc_cal_result |= (rdc << 8) & 0x0000FFFF; 66762306a36Sopenharmony_ci if (rdc_cal_result) 66862306a36Sopenharmony_ci max98390->ref_rdc_value = 268435456U / rdc_cal_result; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci max98390->ambient_temp_value = temp * 52 - 1188; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci rdc_integer = rdc_cal_result * 937 / 65536; 67362306a36Sopenharmony_ci rdc_factor = ((rdc_cal_result * 937 * 100) / 65536) - (rdc_integer * 100); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci dev_info(component->dev, 67662306a36Sopenharmony_ci "rdc resistance about %d.%02d ohm, reg=0x%X temp reg=0x%X\n", 67762306a36Sopenharmony_ci rdc_integer, rdc_factor, rdc_cal_result, temp); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci return 0; 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic const struct snd_kcontrol_new max98390_snd_controls[] = { 68362306a36Sopenharmony_ci SOC_SINGLE_TLV("Digital Volume", DSM_VOL_CTRL, 68462306a36Sopenharmony_ci 0, 184, 0, 68562306a36Sopenharmony_ci max98390_digital_tlv), 68662306a36Sopenharmony_ci SOC_SINGLE_TLV("Speaker Volume", MAX98390_R203D_SPK_GAIN, 68762306a36Sopenharmony_ci 0, 6, 0, 68862306a36Sopenharmony_ci max98390_spk_tlv), 68962306a36Sopenharmony_ci SOC_SINGLE("Ramp Up Bypass Switch", MAX98390_R2039_AMP_DSP_CFG, 69062306a36Sopenharmony_ci MAX98390_AMP_DSP_CFG_RMP_UP_SHIFT, 1, 0), 69162306a36Sopenharmony_ci SOC_SINGLE("Ramp Down Bypass Switch", MAX98390_R2039_AMP_DSP_CFG, 69262306a36Sopenharmony_ci MAX98390_AMP_DSP_CFG_RMP_DN_SHIFT, 1, 0), 69362306a36Sopenharmony_ci SOC_SINGLE("Boost Clock Phase", MAX98390_BOOST_CTRL3, 69462306a36Sopenharmony_ci MAX98390_BOOST_CLK_PHASE_CFG_SHIFT, 3, 0), 69562306a36Sopenharmony_ci SOC_ENUM("Boost Output Voltage", max98390_boost_voltage), 69662306a36Sopenharmony_ci SOC_ENUM("Current Limit", max98390_current_limit), 69762306a36Sopenharmony_ci SOC_SINGLE_EXT("DSM Rdc", SND_SOC_NOPM, 0, 0xffffff, 0, 69862306a36Sopenharmony_ci max98390_ref_rdc_get, max98390_ref_rdc_put), 69962306a36Sopenharmony_ci SOC_SINGLE_EXT("DSM Ambient Temp", SND_SOC_NOPM, 0, 0xffff, 0, 70062306a36Sopenharmony_ci max98390_ambient_temp_get, max98390_ambient_temp_put), 70162306a36Sopenharmony_ci SOC_SINGLE_EXT("DSM Adaptive Rdc", SND_SOC_NOPM, 0, 0xffff, 0, 70262306a36Sopenharmony_ci max98390_adaptive_rdc_get, max98390_adaptive_rdc_put), 70362306a36Sopenharmony_ci SOC_SINGLE_EXT("DSM Calibration", SND_SOC_NOPM, 0, 1, 0, 70462306a36Sopenharmony_ci max98390_dsm_calib_get, max98390_dsm_calib_put), 70562306a36Sopenharmony_ci}; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_cistatic const struct soc_enum dai_sel_enum = 70862306a36Sopenharmony_ci SOC_ENUM_SINGLE(MAX98390_PCM_CH_SRC_1, 70962306a36Sopenharmony_ci MAX98390_PCM_RX_CH_SRC_SHIFT, 71062306a36Sopenharmony_ci 3, max98390_switch_text); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_cistatic const struct snd_kcontrol_new max98390_dai_controls = 71362306a36Sopenharmony_ci SOC_DAPM_ENUM("DAI Sel", dai_sel_enum); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget max98390_dapm_widgets[] = { 71662306a36Sopenharmony_ci SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", 71762306a36Sopenharmony_ci SND_SOC_NOPM, 0, 0, max98390_dac_event, 71862306a36Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 71962306a36Sopenharmony_ci SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0, 72062306a36Sopenharmony_ci &max98390_dai_controls), 72162306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("BE_OUT"), 72262306a36Sopenharmony_ci}; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic const struct snd_soc_dapm_route max98390_audio_map[] = { 72562306a36Sopenharmony_ci /* Plabyack */ 72662306a36Sopenharmony_ci {"DAI Sel Mux", "Left", "Amp Enable"}, 72762306a36Sopenharmony_ci {"DAI Sel Mux", "Right", "Amp Enable"}, 72862306a36Sopenharmony_ci {"DAI Sel Mux", "LeftRight", "Amp Enable"}, 72962306a36Sopenharmony_ci {"BE_OUT", NULL, "DAI Sel Mux"}, 73062306a36Sopenharmony_ci}; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_cistatic bool max98390_readable_register(struct device *dev, unsigned int reg) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci switch (reg) { 73562306a36Sopenharmony_ci case MAX98390_SOFTWARE_RESET ... MAX98390_INT_EN3: 73662306a36Sopenharmony_ci case MAX98390_IRQ_CTRL ... MAX98390_WDOG_CTRL: 73762306a36Sopenharmony_ci case MAX98390_MEAS_ADC_THERM_WARN_THRESH 73862306a36Sopenharmony_ci ... MAX98390_BROWNOUT_INFINITE_HOLD: 73962306a36Sopenharmony_ci case MAX98390_BROWNOUT_LVL_HOLD ... DSMIG_DEBUZZER_THRESHOLD: 74062306a36Sopenharmony_ci case DSM_VOL_ENA ... MAX98390_R24FF_REV_ID: 74162306a36Sopenharmony_ci return true; 74262306a36Sopenharmony_ci default: 74362306a36Sopenharmony_ci return false; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci}; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic bool max98390_volatile_reg(struct device *dev, unsigned int reg) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci switch (reg) { 75062306a36Sopenharmony_ci case MAX98390_SOFTWARE_RESET ... MAX98390_INT_EN3: 75162306a36Sopenharmony_ci case MAX98390_MEAS_ADC_CH0_READ ... MAX98390_MEAS_ADC_CH2_READ: 75262306a36Sopenharmony_ci case MAX98390_PWR_GATE_STATUS ... MAX98390_BROWNOUT_STATUS: 75362306a36Sopenharmony_ci case MAX98390_BROWNOUT_LOWEST_STATUS: 75462306a36Sopenharmony_ci case MAX98390_ENV_TRACK_BOOST_VOUT_READ: 75562306a36Sopenharmony_ci case DSM_STBASS_HPF_B0_BYTE0 ... DSM_DEBUZZER_ATTACK_TIME_BYTE2: 75662306a36Sopenharmony_ci case THERMAL_RDC_RD_BACK_BYTE1 ... DSMIG_DEBUZZER_THRESHOLD: 75762306a36Sopenharmony_ci case DSM_THERMAL_GAIN ... DSM_WBDRC_GAIN: 75862306a36Sopenharmony_ci return true; 75962306a36Sopenharmony_ci default: 76062306a36Sopenharmony_ci return false; 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci#define MAX98390_RATES SNDRV_PCM_RATE_8000_48000 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci#define MAX98390_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 76762306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_cistatic struct snd_soc_dai_driver max98390_dai[] = { 77062306a36Sopenharmony_ci { 77162306a36Sopenharmony_ci .name = "max98390-aif1", 77262306a36Sopenharmony_ci .playback = { 77362306a36Sopenharmony_ci .stream_name = "HiFi Playback", 77462306a36Sopenharmony_ci .channels_min = 1, 77562306a36Sopenharmony_ci .channels_max = 2, 77662306a36Sopenharmony_ci .rates = MAX98390_RATES, 77762306a36Sopenharmony_ci .formats = MAX98390_FORMATS, 77862306a36Sopenharmony_ci }, 77962306a36Sopenharmony_ci .capture = { 78062306a36Sopenharmony_ci .stream_name = "HiFi Capture", 78162306a36Sopenharmony_ci .channels_min = 1, 78262306a36Sopenharmony_ci .channels_max = 2, 78362306a36Sopenharmony_ci .rates = MAX98390_RATES, 78462306a36Sopenharmony_ci .formats = MAX98390_FORMATS, 78562306a36Sopenharmony_ci }, 78662306a36Sopenharmony_ci .ops = &max98390_dai_ops, 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci}; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_cistatic int max98390_dsm_init(struct snd_soc_component *component) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci int ret; 79362306a36Sopenharmony_ci int param_size, param_start_addr; 79462306a36Sopenharmony_ci char filename[128]; 79562306a36Sopenharmony_ci const char *vendor, *product; 79662306a36Sopenharmony_ci struct max98390_priv *max98390 = 79762306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 79862306a36Sopenharmony_ci const struct firmware *fw; 79962306a36Sopenharmony_ci char *dsm_param; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci vendor = dmi_get_system_info(DMI_SYS_VENDOR); 80262306a36Sopenharmony_ci product = dmi_get_system_info(DMI_PRODUCT_NAME); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci if (!strcmp(max98390->dsm_param_name, "default")) { 80562306a36Sopenharmony_ci if (vendor && product) { 80662306a36Sopenharmony_ci snprintf(filename, sizeof(filename), 80762306a36Sopenharmony_ci "dsm_param_%s_%s.bin", vendor, product); 80862306a36Sopenharmony_ci } else { 80962306a36Sopenharmony_ci sprintf(filename, "dsm_param.bin"); 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci } else { 81262306a36Sopenharmony_ci snprintf(filename, sizeof(filename), "%s", 81362306a36Sopenharmony_ci max98390->dsm_param_name); 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci ret = request_firmware(&fw, filename, component->dev); 81662306a36Sopenharmony_ci if (ret) { 81762306a36Sopenharmony_ci ret = request_firmware(&fw, "dsm_param.bin", component->dev); 81862306a36Sopenharmony_ci if (ret) { 81962306a36Sopenharmony_ci ret = request_firmware(&fw, "dsmparam.bin", 82062306a36Sopenharmony_ci component->dev); 82162306a36Sopenharmony_ci if (ret) 82262306a36Sopenharmony_ci goto err; 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci dev_dbg(component->dev, 82762306a36Sopenharmony_ci "max98390: param fw size %zd\n", 82862306a36Sopenharmony_ci fw->size); 82962306a36Sopenharmony_ci if (fw->size < MAX98390_DSM_PARAM_MIN_SIZE) { 83062306a36Sopenharmony_ci dev_err(component->dev, 83162306a36Sopenharmony_ci "param fw is invalid.\n"); 83262306a36Sopenharmony_ci ret = -EINVAL; 83362306a36Sopenharmony_ci goto err_alloc; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci dsm_param = (char *)fw->data; 83662306a36Sopenharmony_ci param_start_addr = (dsm_param[0] & 0xff) | (dsm_param[1] & 0xff) << 8; 83762306a36Sopenharmony_ci param_size = (dsm_param[2] & 0xff) | (dsm_param[3] & 0xff) << 8; 83862306a36Sopenharmony_ci if (param_size > MAX98390_DSM_PARAM_MAX_SIZE || 83962306a36Sopenharmony_ci param_start_addr < MAX98390_IRQ_CTRL || 84062306a36Sopenharmony_ci fw->size < param_size + MAX98390_DSM_PAYLOAD_OFFSET) { 84162306a36Sopenharmony_ci dev_err(component->dev, 84262306a36Sopenharmony_ci "param fw is invalid.\n"); 84362306a36Sopenharmony_ci ret = -EINVAL; 84462306a36Sopenharmony_ci goto err_alloc; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_R203A_AMP_EN, 0x80); 84762306a36Sopenharmony_ci dsm_param += MAX98390_DSM_PAYLOAD_OFFSET; 84862306a36Sopenharmony_ci regmap_bulk_write(max98390->regmap, param_start_addr, 84962306a36Sopenharmony_ci dsm_param, param_size); 85062306a36Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_R23E1_DSP_GLOBAL_EN, 0x01); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_cierr_alloc: 85362306a36Sopenharmony_ci release_firmware(fw); 85462306a36Sopenharmony_cierr: 85562306a36Sopenharmony_ci return ret; 85662306a36Sopenharmony_ci} 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistatic void max98390_init_regs(struct snd_soc_component *component) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci struct max98390_priv *max98390 = 86162306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_CLK_MON, 0x6f); 86462306a36Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_DAT_MON, 0x00); 86562306a36Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_PWR_GATE_CTL, 0x00); 86662306a36Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_PCM_RX_EN_A, 0x03); 86762306a36Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_ENV_TRACK_VOUT_HEADROOM, 0x0e); 86862306a36Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_BOOST_BYPASS1, 0x46); 86962306a36Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_FET_SCALING3, 0x03); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci /* voltage, current slot configuration */ 87262306a36Sopenharmony_ci regmap_write(max98390->regmap, 87362306a36Sopenharmony_ci MAX98390_PCM_CH_SRC_2, 87462306a36Sopenharmony_ci (max98390->i_l_slot << 4 | 87562306a36Sopenharmony_ci max98390->v_l_slot)&0xFF); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (max98390->v_l_slot < 8) { 87862306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 87962306a36Sopenharmony_ci MAX98390_PCM_TX_HIZ_CTRL_A, 88062306a36Sopenharmony_ci 1 << max98390->v_l_slot, 0); 88162306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 88262306a36Sopenharmony_ci MAX98390_PCM_TX_EN_A, 88362306a36Sopenharmony_ci 1 << max98390->v_l_slot, 88462306a36Sopenharmony_ci 1 << max98390->v_l_slot); 88562306a36Sopenharmony_ci } else { 88662306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 88762306a36Sopenharmony_ci MAX98390_PCM_TX_HIZ_CTRL_B, 88862306a36Sopenharmony_ci 1 << (max98390->v_l_slot - 8), 0); 88962306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 89062306a36Sopenharmony_ci MAX98390_PCM_TX_EN_B, 89162306a36Sopenharmony_ci 1 << (max98390->v_l_slot - 8), 89262306a36Sopenharmony_ci 1 << (max98390->v_l_slot - 8)); 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci if (max98390->i_l_slot < 8) { 89662306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 89762306a36Sopenharmony_ci MAX98390_PCM_TX_HIZ_CTRL_A, 89862306a36Sopenharmony_ci 1 << max98390->i_l_slot, 0); 89962306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 90062306a36Sopenharmony_ci MAX98390_PCM_TX_EN_A, 90162306a36Sopenharmony_ci 1 << max98390->i_l_slot, 90262306a36Sopenharmony_ci 1 << max98390->i_l_slot); 90362306a36Sopenharmony_ci } else { 90462306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 90562306a36Sopenharmony_ci MAX98390_PCM_TX_HIZ_CTRL_B, 90662306a36Sopenharmony_ci 1 << (max98390->i_l_slot - 8), 0); 90762306a36Sopenharmony_ci regmap_update_bits(max98390->regmap, 90862306a36Sopenharmony_ci MAX98390_PCM_TX_EN_B, 90962306a36Sopenharmony_ci 1 << (max98390->i_l_slot - 8), 91062306a36Sopenharmony_ci 1 << (max98390->i_l_slot - 8)); 91162306a36Sopenharmony_ci } 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_cistatic int max98390_probe(struct snd_soc_component *component) 91562306a36Sopenharmony_ci{ 91662306a36Sopenharmony_ci struct max98390_priv *max98390 = 91762306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_SOFTWARE_RESET, 0x01); 92062306a36Sopenharmony_ci /* Sleep reset settle time */ 92162306a36Sopenharmony_ci msleep(20); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci /* Amp init setting */ 92462306a36Sopenharmony_ci max98390_init_regs(component); 92562306a36Sopenharmony_ci /* Update dsm bin param */ 92662306a36Sopenharmony_ci max98390_dsm_init(component); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci /* Dsm Setting */ 92962306a36Sopenharmony_ci if (max98390->ref_rdc_value) { 93062306a36Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_RECIP_RDC_ROOM_BYTE0, 93162306a36Sopenharmony_ci max98390->ref_rdc_value & 0x000000ff); 93262306a36Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_RECIP_RDC_ROOM_BYTE1, 93362306a36Sopenharmony_ci (max98390->ref_rdc_value >> 8) & 0x000000ff); 93462306a36Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_RECIP_RDC_ROOM_BYTE2, 93562306a36Sopenharmony_ci (max98390->ref_rdc_value >> 16) & 0x000000ff); 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci if (max98390->ambient_temp_value) { 93862306a36Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_ROOM_TEMPERATURE_BYTE1, 93962306a36Sopenharmony_ci (max98390->ambient_temp_value >> 8) & 0x000000ff); 94062306a36Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_ROOM_TEMPERATURE_BYTE0, 94162306a36Sopenharmony_ci (max98390->ambient_temp_value) & 0x000000ff); 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci return 0; 94562306a36Sopenharmony_ci} 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 94862306a36Sopenharmony_cistatic int max98390_suspend(struct device *dev) 94962306a36Sopenharmony_ci{ 95062306a36Sopenharmony_ci struct max98390_priv *max98390 = dev_get_drvdata(dev); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci dev_dbg(dev, "%s:Enter\n", __func__); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci regcache_cache_only(max98390->regmap, true); 95562306a36Sopenharmony_ci regcache_mark_dirty(max98390->regmap); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci return 0; 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_cistatic int max98390_resume(struct device *dev) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci struct max98390_priv *max98390 = dev_get_drvdata(dev); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci dev_dbg(dev, "%s:Enter\n", __func__); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci regcache_cache_only(max98390->regmap, false); 96762306a36Sopenharmony_ci regcache_sync(max98390->regmap); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci return 0; 97062306a36Sopenharmony_ci} 97162306a36Sopenharmony_ci#endif 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_cistatic const struct dev_pm_ops max98390_pm = { 97462306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(max98390_suspend, max98390_resume) 97562306a36Sopenharmony_ci}; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_codec_dev_max98390 = { 97862306a36Sopenharmony_ci .probe = max98390_probe, 97962306a36Sopenharmony_ci .controls = max98390_snd_controls, 98062306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(max98390_snd_controls), 98162306a36Sopenharmony_ci .dapm_widgets = max98390_dapm_widgets, 98262306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(max98390_dapm_widgets), 98362306a36Sopenharmony_ci .dapm_routes = max98390_audio_map, 98462306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(max98390_audio_map), 98562306a36Sopenharmony_ci .idle_bias_on = 1, 98662306a36Sopenharmony_ci .use_pmdown_time = 1, 98762306a36Sopenharmony_ci .endianness = 1, 98862306a36Sopenharmony_ci}; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_cistatic const struct regmap_config max98390_regmap = { 99162306a36Sopenharmony_ci .reg_bits = 16, 99262306a36Sopenharmony_ci .val_bits = 8, 99362306a36Sopenharmony_ci .max_register = MAX98390_R24FF_REV_ID, 99462306a36Sopenharmony_ci .reg_defaults = max98390_reg_defaults, 99562306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(max98390_reg_defaults), 99662306a36Sopenharmony_ci .readable_reg = max98390_readable_register, 99762306a36Sopenharmony_ci .volatile_reg = max98390_volatile_reg, 99862306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 99962306a36Sopenharmony_ci}; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_cistatic void max98390_slot_config(struct i2c_client *i2c, 100262306a36Sopenharmony_ci struct max98390_priv *max98390) 100362306a36Sopenharmony_ci{ 100462306a36Sopenharmony_ci int value; 100562306a36Sopenharmony_ci struct device *dev = &i2c->dev; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci if (!device_property_read_u32(dev, "maxim,vmon-slot-no", &value)) 100862306a36Sopenharmony_ci max98390->v_l_slot = value & 0xF; 100962306a36Sopenharmony_ci else 101062306a36Sopenharmony_ci max98390->v_l_slot = 0; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci if (!device_property_read_u32(dev, "maxim,imon-slot-no", &value)) 101362306a36Sopenharmony_ci max98390->i_l_slot = value & 0xF; 101462306a36Sopenharmony_ci else 101562306a36Sopenharmony_ci max98390->i_l_slot = 1; 101662306a36Sopenharmony_ci} 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_cistatic int max98390_i2c_probe(struct i2c_client *i2c) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci int ret = 0; 102162306a36Sopenharmony_ci int reg = 0; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci struct max98390_priv *max98390 = NULL; 102462306a36Sopenharmony_ci struct i2c_adapter *adapter = i2c->adapter; 102562306a36Sopenharmony_ci struct gpio_desc *reset_gpio; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci ret = i2c_check_functionality(adapter, 102862306a36Sopenharmony_ci I2C_FUNC_SMBUS_BYTE 102962306a36Sopenharmony_ci | I2C_FUNC_SMBUS_BYTE_DATA); 103062306a36Sopenharmony_ci if (!ret) { 103162306a36Sopenharmony_ci dev_err(&i2c->dev, "I2C check functionality failed\n"); 103262306a36Sopenharmony_ci return -ENXIO; 103362306a36Sopenharmony_ci } 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci max98390 = devm_kzalloc(&i2c->dev, sizeof(*max98390), GFP_KERNEL); 103662306a36Sopenharmony_ci if (!max98390) { 103762306a36Sopenharmony_ci ret = -ENOMEM; 103862306a36Sopenharmony_ci return ret; 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci i2c_set_clientdata(i2c, max98390); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci ret = device_property_read_u32(&i2c->dev, "maxim,temperature_calib", 104362306a36Sopenharmony_ci &max98390->ambient_temp_value); 104462306a36Sopenharmony_ci if (ret) { 104562306a36Sopenharmony_ci dev_info(&i2c->dev, 104662306a36Sopenharmony_ci "no optional property 'temperature_calib' found, default:\n"); 104762306a36Sopenharmony_ci } 104862306a36Sopenharmony_ci ret = device_property_read_u32(&i2c->dev, "maxim,r0_calib", 104962306a36Sopenharmony_ci &max98390->ref_rdc_value); 105062306a36Sopenharmony_ci if (ret) { 105162306a36Sopenharmony_ci dev_info(&i2c->dev, 105262306a36Sopenharmony_ci "no optional property 'r0_calib' found, default:\n"); 105362306a36Sopenharmony_ci } 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci dev_info(&i2c->dev, 105662306a36Sopenharmony_ci "%s: r0_calib: 0x%x,temperature_calib: 0x%x", 105762306a36Sopenharmony_ci __func__, max98390->ref_rdc_value, 105862306a36Sopenharmony_ci max98390->ambient_temp_value); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci ret = device_property_read_string(&i2c->dev, "maxim,dsm_param_name", 106162306a36Sopenharmony_ci &max98390->dsm_param_name); 106262306a36Sopenharmony_ci if (ret) 106362306a36Sopenharmony_ci max98390->dsm_param_name = "default"; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci /* voltage/current slot configuration */ 106662306a36Sopenharmony_ci max98390_slot_config(i2c, max98390); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci /* regmap initialization */ 106962306a36Sopenharmony_ci max98390->regmap = devm_regmap_init_i2c(i2c, &max98390_regmap); 107062306a36Sopenharmony_ci if (IS_ERR(max98390->regmap)) { 107162306a36Sopenharmony_ci ret = PTR_ERR(max98390->regmap); 107262306a36Sopenharmony_ci dev_err(&i2c->dev, 107362306a36Sopenharmony_ci "Failed to allocate regmap: %d\n", ret); 107462306a36Sopenharmony_ci return ret; 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci reset_gpio = devm_gpiod_get_optional(&i2c->dev, 107862306a36Sopenharmony_ci "reset", GPIOD_OUT_HIGH); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci /* Power on device */ 108162306a36Sopenharmony_ci if (reset_gpio) { 108262306a36Sopenharmony_ci usleep_range(1000, 2000); 108362306a36Sopenharmony_ci /* bring out of reset */ 108462306a36Sopenharmony_ci gpiod_set_value_cansleep(reset_gpio, 0); 108562306a36Sopenharmony_ci usleep_range(1000, 2000); 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci /* Check Revision ID */ 108962306a36Sopenharmony_ci ret = regmap_read(max98390->regmap, 109062306a36Sopenharmony_ci MAX98390_R24FF_REV_ID, ®); 109162306a36Sopenharmony_ci if (ret) { 109262306a36Sopenharmony_ci dev_err(&i2c->dev, 109362306a36Sopenharmony_ci "ret=%d, Failed to read: 0x%02X\n", 109462306a36Sopenharmony_ci ret, MAX98390_R24FF_REV_ID); 109562306a36Sopenharmony_ci return ret; 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci dev_info(&i2c->dev, "MAX98390 revisionID: 0x%02X\n", reg); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci ret = devm_snd_soc_register_component(&i2c->dev, 110062306a36Sopenharmony_ci &soc_codec_dev_max98390, 110162306a36Sopenharmony_ci max98390_dai, ARRAY_SIZE(max98390_dai)); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci return ret; 110462306a36Sopenharmony_ci} 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_cistatic const struct i2c_device_id max98390_i2c_id[] = { 110762306a36Sopenharmony_ci { "max98390", 0}, 110862306a36Sopenharmony_ci {}, 110962306a36Sopenharmony_ci}; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, max98390_i2c_id); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci#if defined(CONFIG_OF) 111462306a36Sopenharmony_cistatic const struct of_device_id max98390_of_match[] = { 111562306a36Sopenharmony_ci { .compatible = "maxim,max98390", }, 111662306a36Sopenharmony_ci {} 111762306a36Sopenharmony_ci}; 111862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, max98390_of_match); 111962306a36Sopenharmony_ci#endif 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci#ifdef CONFIG_ACPI 112262306a36Sopenharmony_cistatic const struct acpi_device_id max98390_acpi_match[] = { 112362306a36Sopenharmony_ci { "MX98390", 0 }, 112462306a36Sopenharmony_ci {}, 112562306a36Sopenharmony_ci}; 112662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, max98390_acpi_match); 112762306a36Sopenharmony_ci#endif 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cistatic struct i2c_driver max98390_i2c_driver = { 113062306a36Sopenharmony_ci .driver = { 113162306a36Sopenharmony_ci .name = "max98390", 113262306a36Sopenharmony_ci .of_match_table = of_match_ptr(max98390_of_match), 113362306a36Sopenharmony_ci .acpi_match_table = ACPI_PTR(max98390_acpi_match), 113462306a36Sopenharmony_ci .pm = &max98390_pm, 113562306a36Sopenharmony_ci }, 113662306a36Sopenharmony_ci .probe = max98390_i2c_probe, 113762306a36Sopenharmony_ci .id_table = max98390_i2c_id, 113862306a36Sopenharmony_ci}; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_cimodule_i2c_driver(max98390_i2c_driver) 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ciMODULE_DESCRIPTION("ALSA SoC MAX98390 driver"); 114362306a36Sopenharmony_ciMODULE_AUTHOR("Steve Lee <steves.lee@maximintegrated.com>"); 114462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1145