18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * max98390.c -- MAX98390 ALSA Soc Audio driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2020 Maxim Integrated Products 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/acpi.h> 108c2ecf20Sopenharmony_ci#include <linux/cdev.h> 118c2ecf20Sopenharmony_ci#include <linux/dmi.h> 128c2ecf20Sopenharmony_ci#include <linux/firmware.h> 138c2ecf20Sopenharmony_ci#include <linux/gpio.h> 148c2ecf20Sopenharmony_ci#include <linux/i2c.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 178c2ecf20Sopenharmony_ci#include <linux/regmap.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <linux/time.h> 208c2ecf20Sopenharmony_ci#include <sound/pcm.h> 218c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 228c2ecf20Sopenharmony_ci#include <sound/soc.h> 238c2ecf20Sopenharmony_ci#include <sound/tlv.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "max98390.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic struct reg_default max98390_reg_defaults[] = { 288c2ecf20Sopenharmony_ci {MAX98390_INT_EN1, 0xf0}, 298c2ecf20Sopenharmony_ci {MAX98390_INT_EN2, 0x00}, 308c2ecf20Sopenharmony_ci {MAX98390_INT_EN3, 0x00}, 318c2ecf20Sopenharmony_ci {MAX98390_INT_FLAG_CLR1, 0x00}, 328c2ecf20Sopenharmony_ci {MAX98390_INT_FLAG_CLR2, 0x00}, 338c2ecf20Sopenharmony_ci {MAX98390_INT_FLAG_CLR3, 0x00}, 348c2ecf20Sopenharmony_ci {MAX98390_IRQ_CTRL, 0x01}, 358c2ecf20Sopenharmony_ci {MAX98390_CLK_MON, 0x6d}, 368c2ecf20Sopenharmony_ci {MAX98390_DAT_MON, 0x03}, 378c2ecf20Sopenharmony_ci {MAX98390_WDOG_CTRL, 0x00}, 388c2ecf20Sopenharmony_ci {MAX98390_WDOG_RST, 0x00}, 398c2ecf20Sopenharmony_ci {MAX98390_MEAS_ADC_THERM_WARN_THRESH, 0x75}, 408c2ecf20Sopenharmony_ci {MAX98390_MEAS_ADC_THERM_SHDN_THRESH, 0x8c}, 418c2ecf20Sopenharmony_ci {MAX98390_MEAS_ADC_THERM_HYSTERESIS, 0x08}, 428c2ecf20Sopenharmony_ci {MAX98390_PIN_CFG, 0x55}, 438c2ecf20Sopenharmony_ci {MAX98390_PCM_RX_EN_A, 0x00}, 448c2ecf20Sopenharmony_ci {MAX98390_PCM_RX_EN_B, 0x00}, 458c2ecf20Sopenharmony_ci {MAX98390_PCM_TX_EN_A, 0x00}, 468c2ecf20Sopenharmony_ci {MAX98390_PCM_TX_EN_B, 0x00}, 478c2ecf20Sopenharmony_ci {MAX98390_PCM_TX_HIZ_CTRL_A, 0xff}, 488c2ecf20Sopenharmony_ci {MAX98390_PCM_TX_HIZ_CTRL_B, 0xff}, 498c2ecf20Sopenharmony_ci {MAX98390_PCM_CH_SRC_1, 0x00}, 508c2ecf20Sopenharmony_ci {MAX98390_PCM_CH_SRC_2, 0x00}, 518c2ecf20Sopenharmony_ci {MAX98390_PCM_CH_SRC_3, 0x00}, 528c2ecf20Sopenharmony_ci {MAX98390_PCM_MODE_CFG, 0xc0}, 538c2ecf20Sopenharmony_ci {MAX98390_PCM_MASTER_MODE, 0x1c}, 548c2ecf20Sopenharmony_ci {MAX98390_PCM_CLK_SETUP, 0x44}, 558c2ecf20Sopenharmony_ci {MAX98390_PCM_SR_SETUP, 0x08}, 568c2ecf20Sopenharmony_ci {MAX98390_ICC_RX_EN_A, 0x00}, 578c2ecf20Sopenharmony_ci {MAX98390_ICC_RX_EN_B, 0x00}, 588c2ecf20Sopenharmony_ci {MAX98390_ICC_TX_EN_A, 0x00}, 598c2ecf20Sopenharmony_ci {MAX98390_ICC_TX_EN_B, 0x00}, 608c2ecf20Sopenharmony_ci {MAX98390_ICC_HIZ_MANUAL_MODE, 0x00}, 618c2ecf20Sopenharmony_ci {MAX98390_ICC_TX_HIZ_EN_A, 0x00}, 628c2ecf20Sopenharmony_ci {MAX98390_ICC_TX_HIZ_EN_B, 0x00}, 638c2ecf20Sopenharmony_ci {MAX98390_ICC_LNK_EN, 0x00}, 648c2ecf20Sopenharmony_ci {MAX98390_R2039_AMP_DSP_CFG, 0x0f}, 658c2ecf20Sopenharmony_ci {MAX98390_R203A_AMP_EN, 0x81}, 668c2ecf20Sopenharmony_ci {MAX98390_TONE_GEN_DC_CFG, 0x00}, 678c2ecf20Sopenharmony_ci {MAX98390_SPK_SRC_SEL, 0x00}, 688c2ecf20Sopenharmony_ci {MAX98390_SSM_CFG, 0x85}, 698c2ecf20Sopenharmony_ci {MAX98390_MEAS_EN, 0x03}, 708c2ecf20Sopenharmony_ci {MAX98390_MEAS_DSP_CFG, 0x0f}, 718c2ecf20Sopenharmony_ci {MAX98390_BOOST_CTRL0, 0x1c}, 728c2ecf20Sopenharmony_ci {MAX98390_BOOST_CTRL3, 0x01}, 738c2ecf20Sopenharmony_ci {MAX98390_BOOST_CTRL1, 0x40}, 748c2ecf20Sopenharmony_ci {MAX98390_MEAS_ADC_CFG, 0x07}, 758c2ecf20Sopenharmony_ci {MAX98390_MEAS_ADC_BASE_MSB, 0x00}, 768c2ecf20Sopenharmony_ci {MAX98390_MEAS_ADC_BASE_LSB, 0x23}, 778c2ecf20Sopenharmony_ci {MAX98390_ADC_CH0_DIVIDE, 0x00}, 788c2ecf20Sopenharmony_ci {MAX98390_ADC_CH1_DIVIDE, 0x00}, 798c2ecf20Sopenharmony_ci {MAX98390_ADC_CH2_DIVIDE, 0x00}, 808c2ecf20Sopenharmony_ci {MAX98390_ADC_CH0_FILT_CFG, 0x00}, 818c2ecf20Sopenharmony_ci {MAX98390_ADC_CH1_FILT_CFG, 0x00}, 828c2ecf20Sopenharmony_ci {MAX98390_ADC_CH2_FILT_CFG, 0x00}, 838c2ecf20Sopenharmony_ci {MAX98390_PWR_GATE_CTL, 0x2c}, 848c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_EN, 0x00}, 858c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_INFINITE_HOLD, 0x00}, 868c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_INFINITE_HOLD_CLR, 0x00}, 878c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL_HOLD, 0x00}, 888c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL1_THRESH, 0x00}, 898c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL2_THRESH, 0x00}, 908c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL3_THRESH, 0x00}, 918c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL4_THRESH, 0x00}, 928c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_THRESH_HYSTERYSIS, 0x00}, 938c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_AMP_LIMITER_ATK_REL, 0x1f}, 948c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_AMP_GAIN_ATK_REL, 0x00}, 958c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_AMP1_CLIP_MODE, 0x00}, 968c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL1_CUR_LIMIT, 0x00}, 978c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL1_AMP1_CTRL1, 0x00}, 988c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL1_AMP1_CTRL2, 0x00}, 998c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL1_AMP1_CTRL3, 0x00}, 1008c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL2_CUR_LIMIT, 0x00}, 1018c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL2_AMP1_CTRL1, 0x00}, 1028c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL2_AMP1_CTRL2, 0x00}, 1038c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL2_AMP1_CTRL3, 0x00}, 1048c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL3_CUR_LIMIT, 0x00}, 1058c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL3_AMP1_CTRL1, 0x00}, 1068c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL3_AMP1_CTRL2, 0x00}, 1078c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL3_AMP1_CTRL3, 0x00}, 1088c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL4_CUR_LIMIT, 0x00}, 1098c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL4_AMP1_CTRL1, 0x00}, 1108c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL4_AMP1_CTRL2, 0x00}, 1118c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LVL4_AMP1_CTRL3, 0x00}, 1128c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_ILIM_HLD, 0x00}, 1138c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_LIM_HLD, 0x00}, 1148c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_CLIP_HLD, 0x00}, 1158c2ecf20Sopenharmony_ci {MAX98390_BROWNOUT_GAIN_HLD, 0x00}, 1168c2ecf20Sopenharmony_ci {MAX98390_ENV_TRACK_VOUT_HEADROOM, 0x0f}, 1178c2ecf20Sopenharmony_ci {MAX98390_ENV_TRACK_BOOST_VOUT_DELAY, 0x80}, 1188c2ecf20Sopenharmony_ci {MAX98390_ENV_TRACK_REL_RATE, 0x07}, 1198c2ecf20Sopenharmony_ci {MAX98390_ENV_TRACK_HOLD_RATE, 0x07}, 1208c2ecf20Sopenharmony_ci {MAX98390_ENV_TRACK_CTRL, 0x01}, 1218c2ecf20Sopenharmony_ci {MAX98390_BOOST_BYPASS1, 0x49}, 1228c2ecf20Sopenharmony_ci {MAX98390_BOOST_BYPASS2, 0x2b}, 1238c2ecf20Sopenharmony_ci {MAX98390_BOOST_BYPASS3, 0x08}, 1248c2ecf20Sopenharmony_ci {MAX98390_FET_SCALING1, 0x00}, 1258c2ecf20Sopenharmony_ci {MAX98390_FET_SCALING2, 0x03}, 1268c2ecf20Sopenharmony_ci {MAX98390_FET_SCALING3, 0x00}, 1278c2ecf20Sopenharmony_ci {MAX98390_FET_SCALING4, 0x07}, 1288c2ecf20Sopenharmony_ci {MAX98390_SPK_SPEEDUP, 0x00}, 1298c2ecf20Sopenharmony_ci {DSMIG_WB_DRC_RELEASE_TIME_1, 0x00}, 1308c2ecf20Sopenharmony_ci {DSMIG_WB_DRC_RELEASE_TIME_2, 0x00}, 1318c2ecf20Sopenharmony_ci {DSMIG_WB_DRC_ATTACK_TIME_1, 0x00}, 1328c2ecf20Sopenharmony_ci {DSMIG_WB_DRC_ATTACK_TIME_2, 0x00}, 1338c2ecf20Sopenharmony_ci {DSMIG_WB_DRC_COMPRESSION_RATIO, 0x00}, 1348c2ecf20Sopenharmony_ci {DSMIG_WB_DRC_COMPRESSION_THRESHOLD, 0x00}, 1358c2ecf20Sopenharmony_ci {DSMIG_WB_DRC_MAKEUPGAIN, 0x00}, 1368c2ecf20Sopenharmony_ci {DSMIG_WB_DRC_NOISE_GATE_THRESHOLD, 0x00}, 1378c2ecf20Sopenharmony_ci {DSMIG_WBDRC_HPF_ENABLE, 0x00}, 1388c2ecf20Sopenharmony_ci {DSMIG_WB_DRC_TEST_SMOOTHER_OUT_EN, 0x00}, 1398c2ecf20Sopenharmony_ci {DSMIG_PPR_THRESHOLD, 0x00}, 1408c2ecf20Sopenharmony_ci {DSM_STEREO_BASS_CHANNEL_SELECT, 0x00}, 1418c2ecf20Sopenharmony_ci {DSM_TPROT_THRESHOLD_BYTE0, 0x00}, 1428c2ecf20Sopenharmony_ci {DSM_TPROT_THRESHOLD_BYTE1, 0x00}, 1438c2ecf20Sopenharmony_ci {DSM_TPROT_ROOM_TEMPERATURE_BYTE0, 0x00}, 1448c2ecf20Sopenharmony_ci {DSM_TPROT_ROOM_TEMPERATURE_BYTE1, 0x00}, 1458c2ecf20Sopenharmony_ci {DSM_TPROT_RECIP_RDC_ROOM_BYTE0, 0x00}, 1468c2ecf20Sopenharmony_ci {DSM_TPROT_RECIP_RDC_ROOM_BYTE1, 0x00}, 1478c2ecf20Sopenharmony_ci {DSM_TPROT_RECIP_RDC_ROOM_BYTE2, 0x00}, 1488c2ecf20Sopenharmony_ci {DSM_TPROT_RECIP_TCONST_BYTE0, 0x00}, 1498c2ecf20Sopenharmony_ci {DSM_TPROT_RECIP_TCONST_BYTE1, 0x00}, 1508c2ecf20Sopenharmony_ci {DSM_TPROT_RECIP_TCONST_BYTE2, 0x00}, 1518c2ecf20Sopenharmony_ci {DSM_THERMAL_ATTENUATION_SETTINGS, 0x00}, 1528c2ecf20Sopenharmony_ci {DSM_THERMAL_PILOT_TONE_ATTENUATION, 0x00}, 1538c2ecf20Sopenharmony_ci {DSM_TPROT_PG_TEMP_THRESH_BYTE0, 0x00}, 1548c2ecf20Sopenharmony_ci {DSM_TPROT_PG_TEMP_THRESH_BYTE1, 0x00}, 1558c2ecf20Sopenharmony_ci {DSMIG_DEBUZZER_THRESHOLD, 0x00}, 1568c2ecf20Sopenharmony_ci {DSMIG_DEBUZZER_ALPHA_COEF_TEST_ONLY, 0x08}, 1578c2ecf20Sopenharmony_ci {DSM_VOL_ENA, 0x20}, 1588c2ecf20Sopenharmony_ci {DSM_VOL_CTRL, 0xa0}, 1598c2ecf20Sopenharmony_ci {DSMIG_EN, 0x00}, 1608c2ecf20Sopenharmony_ci {MAX98390_R23E1_DSP_GLOBAL_EN, 0x00}, 1618c2ecf20Sopenharmony_ci {MAX98390_R23FF_GLOBAL_EN, 0x00}, 1628c2ecf20Sopenharmony_ci}; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int max98390_dsm_calibrate(struct snd_soc_component *component); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic int max98390_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 1698c2ecf20Sopenharmony_ci struct max98390_priv *max98390 = 1708c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 1718c2ecf20Sopenharmony_ci unsigned int mode; 1728c2ecf20Sopenharmony_ci unsigned int format; 1738c2ecf20Sopenharmony_ci unsigned int invert = 0; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 1788c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBS_CFS: 1798c2ecf20Sopenharmony_ci mode = MAX98390_PCM_MASTER_MODE_SLAVE; 1808c2ecf20Sopenharmony_ci break; 1818c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFM: 1828c2ecf20Sopenharmony_ci max98390->master = true; 1838c2ecf20Sopenharmony_ci mode = MAX98390_PCM_MASTER_MODE_MASTER; 1848c2ecf20Sopenharmony_ci break; 1858c2ecf20Sopenharmony_ci default: 1868c2ecf20Sopenharmony_ci dev_err(component->dev, "DAI clock mode unsupported\n"); 1878c2ecf20Sopenharmony_ci return -EINVAL; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci regmap_update_bits(max98390->regmap, 1918c2ecf20Sopenharmony_ci MAX98390_PCM_MASTER_MODE, 1928c2ecf20Sopenharmony_ci MAX98390_PCM_MASTER_MODE_MASK, 1938c2ecf20Sopenharmony_ci mode); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 1968c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 1998c2ecf20Sopenharmony_ci invert = MAX98390_PCM_MODE_CFG_PCM_BCLKEDGE; 2008c2ecf20Sopenharmony_ci break; 2018c2ecf20Sopenharmony_ci default: 2028c2ecf20Sopenharmony_ci dev_err(component->dev, "DAI invert mode unsupported\n"); 2038c2ecf20Sopenharmony_ci return -EINVAL; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci regmap_update_bits(max98390->regmap, 2078c2ecf20Sopenharmony_ci MAX98390_PCM_MODE_CFG, 2088c2ecf20Sopenharmony_ci MAX98390_PCM_MODE_CFG_PCM_BCLKEDGE, 2098c2ecf20Sopenharmony_ci invert); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* interface format */ 2128c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 2138c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 2148c2ecf20Sopenharmony_ci format = MAX98390_PCM_FORMAT_I2S; 2158c2ecf20Sopenharmony_ci break; 2168c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 2178c2ecf20Sopenharmony_ci format = MAX98390_PCM_FORMAT_LJ; 2188c2ecf20Sopenharmony_ci break; 2198c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 2208c2ecf20Sopenharmony_ci format = MAX98390_PCM_FORMAT_TDM_MODE1; 2218c2ecf20Sopenharmony_ci break; 2228c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 2238c2ecf20Sopenharmony_ci format = MAX98390_PCM_FORMAT_TDM_MODE0; 2248c2ecf20Sopenharmony_ci break; 2258c2ecf20Sopenharmony_ci default: 2268c2ecf20Sopenharmony_ci return -EINVAL; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci regmap_update_bits(max98390->regmap, 2308c2ecf20Sopenharmony_ci MAX98390_PCM_MODE_CFG, 2318c2ecf20Sopenharmony_ci MAX98390_PCM_MODE_CFG_FORMAT_MASK, 2328c2ecf20Sopenharmony_ci format << MAX98390_PCM_MODE_CFG_FORMAT_SHIFT); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return 0; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic int max98390_get_bclk_sel(int bclk) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci int i; 2408c2ecf20Sopenharmony_ci /* BCLKs per LRCLK */ 2418c2ecf20Sopenharmony_ci static int bclk_sel_table[] = { 2428c2ecf20Sopenharmony_ci 32, 48, 64, 96, 128, 192, 256, 320, 384, 512, 2438c2ecf20Sopenharmony_ci }; 2448c2ecf20Sopenharmony_ci /* match BCLKs per LRCLK */ 2458c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) { 2468c2ecf20Sopenharmony_ci if (bclk_sel_table[i] == bclk) 2478c2ecf20Sopenharmony_ci return i + 2; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci return 0; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic int max98390_set_clock(struct snd_soc_component *component, 2538c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci struct max98390_priv *max98390 = 2568c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 2578c2ecf20Sopenharmony_ci /* codec MCLK rate in master mode */ 2588c2ecf20Sopenharmony_ci static int rate_table[] = { 2598c2ecf20Sopenharmony_ci 5644800, 6000000, 6144000, 6500000, 2608c2ecf20Sopenharmony_ci 9600000, 11289600, 12000000, 12288000, 2618c2ecf20Sopenharmony_ci 13000000, 19200000, 2628c2ecf20Sopenharmony_ci }; 2638c2ecf20Sopenharmony_ci /* BCLK/LRCLK ratio calculation */ 2648c2ecf20Sopenharmony_ci int blr_clk_ratio = params_channels(params) 2658c2ecf20Sopenharmony_ci * snd_pcm_format_width(params_format(params)); 2668c2ecf20Sopenharmony_ci int value; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (max98390->master) { 2698c2ecf20Sopenharmony_ci int i; 2708c2ecf20Sopenharmony_ci /* match rate to closest value */ 2718c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rate_table); i++) { 2728c2ecf20Sopenharmony_ci if (rate_table[i] >= max98390->sysclk) 2738c2ecf20Sopenharmony_ci break; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(rate_table)) { 2768c2ecf20Sopenharmony_ci dev_err(component->dev, "failed to find proper clock rate.\n"); 2778c2ecf20Sopenharmony_ci return -EINVAL; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci regmap_update_bits(max98390->regmap, 2818c2ecf20Sopenharmony_ci MAX98390_PCM_MASTER_MODE, 2828c2ecf20Sopenharmony_ci MAX98390_PCM_MASTER_MODE_MCLK_MASK, 2838c2ecf20Sopenharmony_ci i << MAX98390_PCM_MASTER_MODE_MCLK_RATE_SHIFT); 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (!max98390->tdm_mode) { 2878c2ecf20Sopenharmony_ci /* BCLK configuration */ 2888c2ecf20Sopenharmony_ci value = max98390_get_bclk_sel(blr_clk_ratio); 2898c2ecf20Sopenharmony_ci if (!value) { 2908c2ecf20Sopenharmony_ci dev_err(component->dev, "format unsupported %d\n", 2918c2ecf20Sopenharmony_ci params_format(params)); 2928c2ecf20Sopenharmony_ci return -EINVAL; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci regmap_update_bits(max98390->regmap, 2968c2ecf20Sopenharmony_ci MAX98390_PCM_CLK_SETUP, 2978c2ecf20Sopenharmony_ci MAX98390_PCM_CLK_SETUP_BSEL_MASK, 2988c2ecf20Sopenharmony_ci value); 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci return 0; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic int max98390_dai_hw_params(struct snd_pcm_substream *substream, 3048c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 3058c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct snd_soc_component *component = 3088c2ecf20Sopenharmony_ci dai->component; 3098c2ecf20Sopenharmony_ci struct max98390_priv *max98390 = 3108c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci unsigned int sampling_rate; 3138c2ecf20Sopenharmony_ci unsigned int chan_sz; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* pcm mode configuration */ 3168c2ecf20Sopenharmony_ci switch (snd_pcm_format_width(params_format(params))) { 3178c2ecf20Sopenharmony_ci case 16: 3188c2ecf20Sopenharmony_ci chan_sz = MAX98390_PCM_MODE_CFG_CHANSZ_16; 3198c2ecf20Sopenharmony_ci break; 3208c2ecf20Sopenharmony_ci case 24: 3218c2ecf20Sopenharmony_ci chan_sz = MAX98390_PCM_MODE_CFG_CHANSZ_24; 3228c2ecf20Sopenharmony_ci break; 3238c2ecf20Sopenharmony_ci case 32: 3248c2ecf20Sopenharmony_ci chan_sz = MAX98390_PCM_MODE_CFG_CHANSZ_32; 3258c2ecf20Sopenharmony_ci break; 3268c2ecf20Sopenharmony_ci default: 3278c2ecf20Sopenharmony_ci dev_err(component->dev, "format unsupported %d\n", 3288c2ecf20Sopenharmony_ci params_format(params)); 3298c2ecf20Sopenharmony_ci goto err; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci regmap_update_bits(max98390->regmap, 3338c2ecf20Sopenharmony_ci MAX98390_PCM_MODE_CFG, 3348c2ecf20Sopenharmony_ci MAX98390_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci dev_dbg(component->dev, "format supported %d", 3378c2ecf20Sopenharmony_ci params_format(params)); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* sampling rate configuration */ 3408c2ecf20Sopenharmony_ci switch (params_rate(params)) { 3418c2ecf20Sopenharmony_ci case 8000: 3428c2ecf20Sopenharmony_ci sampling_rate = MAX98390_PCM_SR_SET1_SR_8000; 3438c2ecf20Sopenharmony_ci break; 3448c2ecf20Sopenharmony_ci case 11025: 3458c2ecf20Sopenharmony_ci sampling_rate = MAX98390_PCM_SR_SET1_SR_11025; 3468c2ecf20Sopenharmony_ci break; 3478c2ecf20Sopenharmony_ci case 12000: 3488c2ecf20Sopenharmony_ci sampling_rate = MAX98390_PCM_SR_SET1_SR_12000; 3498c2ecf20Sopenharmony_ci break; 3508c2ecf20Sopenharmony_ci case 16000: 3518c2ecf20Sopenharmony_ci sampling_rate = MAX98390_PCM_SR_SET1_SR_16000; 3528c2ecf20Sopenharmony_ci break; 3538c2ecf20Sopenharmony_ci case 22050: 3548c2ecf20Sopenharmony_ci sampling_rate = MAX98390_PCM_SR_SET1_SR_22050; 3558c2ecf20Sopenharmony_ci break; 3568c2ecf20Sopenharmony_ci case 24000: 3578c2ecf20Sopenharmony_ci sampling_rate = MAX98390_PCM_SR_SET1_SR_24000; 3588c2ecf20Sopenharmony_ci break; 3598c2ecf20Sopenharmony_ci case 32000: 3608c2ecf20Sopenharmony_ci sampling_rate = MAX98390_PCM_SR_SET1_SR_32000; 3618c2ecf20Sopenharmony_ci break; 3628c2ecf20Sopenharmony_ci case 44100: 3638c2ecf20Sopenharmony_ci sampling_rate = MAX98390_PCM_SR_SET1_SR_44100; 3648c2ecf20Sopenharmony_ci break; 3658c2ecf20Sopenharmony_ci case 48000: 3668c2ecf20Sopenharmony_ci sampling_rate = MAX98390_PCM_SR_SET1_SR_48000; 3678c2ecf20Sopenharmony_ci break; 3688c2ecf20Sopenharmony_ci default: 3698c2ecf20Sopenharmony_ci dev_err(component->dev, "rate %d not supported\n", 3708c2ecf20Sopenharmony_ci params_rate(params)); 3718c2ecf20Sopenharmony_ci goto err; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci /* set DAI_SR to correct LRCLK frequency */ 3758c2ecf20Sopenharmony_ci regmap_update_bits(max98390->regmap, 3768c2ecf20Sopenharmony_ci MAX98390_PCM_SR_SETUP, 3778c2ecf20Sopenharmony_ci MAX98390_PCM_SR_SET1_SR_MASK, 3788c2ecf20Sopenharmony_ci sampling_rate); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return max98390_set_clock(component, params); 3818c2ecf20Sopenharmony_cierr: 3828c2ecf20Sopenharmony_ci return -EINVAL; 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic int max98390_dai_tdm_slot(struct snd_soc_dai *dai, 3868c2ecf20Sopenharmony_ci unsigned int tx_mask, unsigned int rx_mask, 3878c2ecf20Sopenharmony_ci int slots, int slot_width) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 3908c2ecf20Sopenharmony_ci struct max98390_priv *max98390 = 3918c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci int bsel; 3948c2ecf20Sopenharmony_ci unsigned int chan_sz; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (!tx_mask && !rx_mask && !slots && !slot_width) 3978c2ecf20Sopenharmony_ci max98390->tdm_mode = false; 3988c2ecf20Sopenharmony_ci else 3998c2ecf20Sopenharmony_ci max98390->tdm_mode = true; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci dev_dbg(component->dev, 4028c2ecf20Sopenharmony_ci "Tdm mode : %d\n", max98390->tdm_mode); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci /* BCLK configuration */ 4058c2ecf20Sopenharmony_ci bsel = max98390_get_bclk_sel(slots * slot_width); 4068c2ecf20Sopenharmony_ci if (!bsel) { 4078c2ecf20Sopenharmony_ci dev_err(component->dev, "BCLK %d not supported\n", 4088c2ecf20Sopenharmony_ci slots * slot_width); 4098c2ecf20Sopenharmony_ci return -EINVAL; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci regmap_update_bits(max98390->regmap, 4138c2ecf20Sopenharmony_ci MAX98390_PCM_CLK_SETUP, 4148c2ecf20Sopenharmony_ci MAX98390_PCM_CLK_SETUP_BSEL_MASK, 4158c2ecf20Sopenharmony_ci bsel); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* Channel size configuration */ 4188c2ecf20Sopenharmony_ci switch (slot_width) { 4198c2ecf20Sopenharmony_ci case 16: 4208c2ecf20Sopenharmony_ci chan_sz = MAX98390_PCM_MODE_CFG_CHANSZ_16; 4218c2ecf20Sopenharmony_ci break; 4228c2ecf20Sopenharmony_ci case 24: 4238c2ecf20Sopenharmony_ci chan_sz = MAX98390_PCM_MODE_CFG_CHANSZ_24; 4248c2ecf20Sopenharmony_ci break; 4258c2ecf20Sopenharmony_ci case 32: 4268c2ecf20Sopenharmony_ci chan_sz = MAX98390_PCM_MODE_CFG_CHANSZ_32; 4278c2ecf20Sopenharmony_ci break; 4288c2ecf20Sopenharmony_ci default: 4298c2ecf20Sopenharmony_ci dev_err(component->dev, "format unsupported %d\n", 4308c2ecf20Sopenharmony_ci slot_width); 4318c2ecf20Sopenharmony_ci return -EINVAL; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci regmap_update_bits(max98390->regmap, 4358c2ecf20Sopenharmony_ci MAX98390_PCM_MODE_CFG, 4368c2ecf20Sopenharmony_ci MAX98390_PCM_MODE_CFG_CHANSZ_MASK, chan_sz); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* Rx slot configuration */ 4398c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, 4408c2ecf20Sopenharmony_ci MAX98390_PCM_RX_EN_A, 4418c2ecf20Sopenharmony_ci rx_mask & 0xFF); 4428c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, 4438c2ecf20Sopenharmony_ci MAX98390_PCM_RX_EN_B, 4448c2ecf20Sopenharmony_ci (rx_mask & 0xFF00) >> 8); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci /* Tx slot Hi-Z configuration */ 4478c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, 4488c2ecf20Sopenharmony_ci MAX98390_PCM_TX_HIZ_CTRL_A, 4498c2ecf20Sopenharmony_ci ~tx_mask & 0xFF); 4508c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, 4518c2ecf20Sopenharmony_ci MAX98390_PCM_TX_HIZ_CTRL_B, 4528c2ecf20Sopenharmony_ci (~tx_mask & 0xFF00) >> 8); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci return 0; 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic int max98390_dai_set_sysclk(struct snd_soc_dai *dai, 4588c2ecf20Sopenharmony_ci int clk_id, unsigned int freq, int dir) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 4618c2ecf20Sopenharmony_ci struct max98390_priv *max98390 = 4628c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci max98390->sysclk = freq; 4658c2ecf20Sopenharmony_ci return 0; 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops max98390_dai_ops = { 4698c2ecf20Sopenharmony_ci .set_sysclk = max98390_dai_set_sysclk, 4708c2ecf20Sopenharmony_ci .set_fmt = max98390_dai_set_fmt, 4718c2ecf20Sopenharmony_ci .hw_params = max98390_dai_hw_params, 4728c2ecf20Sopenharmony_ci .set_tdm_slot = max98390_dai_tdm_slot, 4738c2ecf20Sopenharmony_ci}; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic int max98390_dac_event(struct snd_soc_dapm_widget *w, 4768c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci struct snd_soc_component *component = 4798c2ecf20Sopenharmony_ci snd_soc_dapm_to_component(w->dapm); 4808c2ecf20Sopenharmony_ci struct max98390_priv *max98390 = 4818c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci switch (event) { 4848c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 4858c2ecf20Sopenharmony_ci regmap_update_bits(max98390->regmap, 4868c2ecf20Sopenharmony_ci MAX98390_R203A_AMP_EN, 4878c2ecf20Sopenharmony_ci MAX98390_AMP_EN_MASK, 1); 4888c2ecf20Sopenharmony_ci regmap_update_bits(max98390->regmap, 4898c2ecf20Sopenharmony_ci MAX98390_R23FF_GLOBAL_EN, 4908c2ecf20Sopenharmony_ci MAX98390_GLOBAL_EN_MASK, 1); 4918c2ecf20Sopenharmony_ci break; 4928c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMD: 4938c2ecf20Sopenharmony_ci regmap_update_bits(max98390->regmap, 4948c2ecf20Sopenharmony_ci MAX98390_R23FF_GLOBAL_EN, 4958c2ecf20Sopenharmony_ci MAX98390_GLOBAL_EN_MASK, 0); 4968c2ecf20Sopenharmony_ci regmap_update_bits(max98390->regmap, 4978c2ecf20Sopenharmony_ci MAX98390_R203A_AMP_EN, 4988c2ecf20Sopenharmony_ci MAX98390_AMP_EN_MASK, 0); 4998c2ecf20Sopenharmony_ci break; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci return 0; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic const char * const max98390_switch_text[] = { 5058c2ecf20Sopenharmony_ci "Left", "Right", "LeftRight"}; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic const char * const max98390_boost_voltage_text[] = { 5088c2ecf20Sopenharmony_ci "6.5V", "6.625V", "6.75V", "6.875V", "7V", "7.125V", "7.25V", "7.375V", 5098c2ecf20Sopenharmony_ci "7.5V", "7.625V", "7.75V", "7.875V", "8V", "8.125V", "8.25V", "8.375V", 5108c2ecf20Sopenharmony_ci "8.5V", "8.625V", "8.75V", "8.875V", "9V", "9.125V", "9.25V", "9.375V", 5118c2ecf20Sopenharmony_ci "9.5V", "9.625V", "9.75V", "9.875V", "10V" 5128c2ecf20Sopenharmony_ci}; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(max98390_boost_voltage, 5158c2ecf20Sopenharmony_ci MAX98390_BOOST_CTRL0, 0, 5168c2ecf20Sopenharmony_ci max98390_boost_voltage_text); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(max98390_spk_tlv, 300, 300, 0); 5198c2ecf20Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(max98390_digital_tlv, -8000, 50, 0); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic const char * const max98390_current_limit_text[] = { 5228c2ecf20Sopenharmony_ci "0.00A", "0.50A", "1.00A", "1.05A", "1.10A", "1.15A", "1.20A", "1.25A", 5238c2ecf20Sopenharmony_ci "1.30A", "1.35A", "1.40A", "1.45A", "1.50A", "1.55A", "1.60A", "1.65A", 5248c2ecf20Sopenharmony_ci "1.70A", "1.75A", "1.80A", "1.85A", "1.90A", "1.95A", "2.00A", "2.05A", 5258c2ecf20Sopenharmony_ci "2.10A", "2.15A", "2.20A", "2.25A", "2.30A", "2.35A", "2.40A", "2.45A", 5268c2ecf20Sopenharmony_ci "2.50A", "2.55A", "2.60A", "2.65A", "2.70A", "2.75A", "2.80A", "2.85A", 5278c2ecf20Sopenharmony_ci "2.90A", "2.95A", "3.00A", "3.05A", "3.10A", "3.15A", "3.20A", "3.25A", 5288c2ecf20Sopenharmony_ci "3.30A", "3.35A", "3.40A", "3.45A", "3.50A", "3.55A", "3.60A", "3.65A", 5298c2ecf20Sopenharmony_ci "3.70A", "3.75A", "3.80A", "3.85A", "3.90A", "3.95A", "4.00A", "4.05A", 5308c2ecf20Sopenharmony_ci "4.10A" 5318c2ecf20Sopenharmony_ci}; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(max98390_current_limit, 5348c2ecf20Sopenharmony_ci MAX98390_BOOST_CTRL1, 0, 5358c2ecf20Sopenharmony_ci max98390_current_limit_text); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic int max98390_ref_rdc_put(struct snd_kcontrol *kcontrol, 5388c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci struct snd_soc_component *component = 5418c2ecf20Sopenharmony_ci snd_soc_kcontrol_component(kcontrol); 5428c2ecf20Sopenharmony_ci struct max98390_priv *max98390 = 5438c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci max98390->ref_rdc_value = ucontrol->value.integer.value[0]; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_RECIP_RDC_ROOM_BYTE0, 5488c2ecf20Sopenharmony_ci max98390->ref_rdc_value & 0x000000ff); 5498c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_RECIP_RDC_ROOM_BYTE1, 5508c2ecf20Sopenharmony_ci (max98390->ref_rdc_value >> 8) & 0x000000ff); 5518c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_RECIP_RDC_ROOM_BYTE2, 5528c2ecf20Sopenharmony_ci (max98390->ref_rdc_value >> 16) & 0x000000ff); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci return 0; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic int max98390_ref_rdc_get(struct snd_kcontrol *kcontrol, 5588c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci struct snd_soc_component *component = 5618c2ecf20Sopenharmony_ci snd_soc_kcontrol_component(kcontrol); 5628c2ecf20Sopenharmony_ci struct max98390_priv *max98390 = 5638c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = max98390->ref_rdc_value; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci return 0; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic int max98390_ambient_temp_put(struct snd_kcontrol *kcontrol, 5718c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci struct snd_soc_component *component = 5748c2ecf20Sopenharmony_ci snd_soc_kcontrol_component(kcontrol); 5758c2ecf20Sopenharmony_ci struct max98390_priv *max98390 = 5768c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci max98390->ambient_temp_value = ucontrol->value.integer.value[0]; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_ROOM_TEMPERATURE_BYTE1, 5818c2ecf20Sopenharmony_ci (max98390->ambient_temp_value >> 8) & 0x000000ff); 5828c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_ROOM_TEMPERATURE_BYTE0, 5838c2ecf20Sopenharmony_ci (max98390->ambient_temp_value) & 0x000000ff); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci return 0; 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic int max98390_ambient_temp_get(struct snd_kcontrol *kcontrol, 5898c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci struct snd_soc_component *component = 5928c2ecf20Sopenharmony_ci snd_soc_kcontrol_component(kcontrol); 5938c2ecf20Sopenharmony_ci struct max98390_priv *max98390 = 5948c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = max98390->ambient_temp_value; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci return 0; 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic int max98390_adaptive_rdc_put(struct snd_kcontrol *kcontrol, 6028c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci struct snd_soc_component *component = 6058c2ecf20Sopenharmony_ci snd_soc_kcontrol_component(kcontrol); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci dev_warn(component->dev, "Put adaptive rdc not supported\n"); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci return 0; 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic int max98390_adaptive_rdc_get(struct snd_kcontrol *kcontrol, 6138c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 6148c2ecf20Sopenharmony_ci{ 6158c2ecf20Sopenharmony_ci int rdc, rdc0; 6168c2ecf20Sopenharmony_ci struct snd_soc_component *component = 6178c2ecf20Sopenharmony_ci snd_soc_kcontrol_component(kcontrol); 6188c2ecf20Sopenharmony_ci struct max98390_priv *max98390 = 6198c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE1, &rdc); 6228c2ecf20Sopenharmony_ci regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE0, &rdc0); 6238c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = rdc0 | rdc << 8; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci return 0; 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_cistatic int max98390_dsm_calib_get(struct snd_kcontrol *kcontrol, 6298c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci /* Do nothing */ 6328c2ecf20Sopenharmony_ci return 0; 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic int max98390_dsm_calib_put(struct snd_kcontrol *kcontrol, 6368c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci struct snd_soc_component *component = 6398c2ecf20Sopenharmony_ci snd_soc_kcontrol_component(kcontrol); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci max98390_dsm_calibrate(component); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci return 0; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new max98390_snd_controls[] = { 6478c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Digital Volume", DSM_VOL_CTRL, 6488c2ecf20Sopenharmony_ci 0, 184, 0, 6498c2ecf20Sopenharmony_ci max98390_digital_tlv), 6508c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Speaker Volume", MAX98390_R203D_SPK_GAIN, 6518c2ecf20Sopenharmony_ci 0, 6, 0, 6528c2ecf20Sopenharmony_ci max98390_spk_tlv), 6538c2ecf20Sopenharmony_ci SOC_SINGLE("Ramp Up Bypass Switch", MAX98390_R2039_AMP_DSP_CFG, 6548c2ecf20Sopenharmony_ci MAX98390_AMP_DSP_CFG_RMP_UP_SHIFT, 1, 0), 6558c2ecf20Sopenharmony_ci SOC_SINGLE("Ramp Down Bypass Switch", MAX98390_R2039_AMP_DSP_CFG, 6568c2ecf20Sopenharmony_ci MAX98390_AMP_DSP_CFG_RMP_DN_SHIFT, 1, 0), 6578c2ecf20Sopenharmony_ci SOC_SINGLE("Boost Clock Phase", MAX98390_BOOST_CTRL3, 6588c2ecf20Sopenharmony_ci MAX98390_BOOST_CLK_PHASE_CFG_SHIFT, 3, 0), 6598c2ecf20Sopenharmony_ci SOC_ENUM("Boost Output Voltage", max98390_boost_voltage), 6608c2ecf20Sopenharmony_ci SOC_ENUM("Current Limit", max98390_current_limit), 6618c2ecf20Sopenharmony_ci SOC_SINGLE_EXT("DSM Rdc", SND_SOC_NOPM, 0, 0xffffff, 0, 6628c2ecf20Sopenharmony_ci max98390_ref_rdc_get, max98390_ref_rdc_put), 6638c2ecf20Sopenharmony_ci SOC_SINGLE_EXT("DSM Ambient Temp", SND_SOC_NOPM, 0, 0xffff, 0, 6648c2ecf20Sopenharmony_ci max98390_ambient_temp_get, max98390_ambient_temp_put), 6658c2ecf20Sopenharmony_ci SOC_SINGLE_EXT("DSM Adaptive Rdc", SND_SOC_NOPM, 0, 0xffff, 0, 6668c2ecf20Sopenharmony_ci max98390_adaptive_rdc_get, max98390_adaptive_rdc_put), 6678c2ecf20Sopenharmony_ci SOC_SINGLE_EXT("DSM Calibration", SND_SOC_NOPM, 0, 1, 0, 6688c2ecf20Sopenharmony_ci max98390_dsm_calib_get, max98390_dsm_calib_put), 6698c2ecf20Sopenharmony_ci}; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic const struct soc_enum dai_sel_enum = 6728c2ecf20Sopenharmony_ci SOC_ENUM_SINGLE(MAX98390_PCM_CH_SRC_1, 6738c2ecf20Sopenharmony_ci MAX98390_PCM_RX_CH_SRC_SHIFT, 6748c2ecf20Sopenharmony_ci 3, max98390_switch_text); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new max98390_dai_controls = 6778c2ecf20Sopenharmony_ci SOC_DAPM_ENUM("DAI Sel", dai_sel_enum); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget max98390_dapm_widgets[] = { 6808c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", 6818c2ecf20Sopenharmony_ci SND_SOC_NOPM, 0, 0, max98390_dac_event, 6828c2ecf20Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 6838c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0, 6848c2ecf20Sopenharmony_ci &max98390_dai_controls), 6858c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("BE_OUT"), 6868c2ecf20Sopenharmony_ci}; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route max98390_audio_map[] = { 6898c2ecf20Sopenharmony_ci /* Plabyack */ 6908c2ecf20Sopenharmony_ci {"DAI Sel Mux", "Left", "Amp Enable"}, 6918c2ecf20Sopenharmony_ci {"DAI Sel Mux", "Right", "Amp Enable"}, 6928c2ecf20Sopenharmony_ci {"DAI Sel Mux", "LeftRight", "Amp Enable"}, 6938c2ecf20Sopenharmony_ci {"BE_OUT", NULL, "DAI Sel Mux"}, 6948c2ecf20Sopenharmony_ci}; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_cistatic bool max98390_readable_register(struct device *dev, unsigned int reg) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci switch (reg) { 6998c2ecf20Sopenharmony_ci case MAX98390_SOFTWARE_RESET ... MAX98390_INT_EN3: 7008c2ecf20Sopenharmony_ci case MAX98390_IRQ_CTRL ... MAX98390_WDOG_CTRL: 7018c2ecf20Sopenharmony_ci case MAX98390_MEAS_ADC_THERM_WARN_THRESH 7028c2ecf20Sopenharmony_ci ... MAX98390_BROWNOUT_INFINITE_HOLD: 7038c2ecf20Sopenharmony_ci case MAX98390_BROWNOUT_LVL_HOLD ... DSMIG_DEBUZZER_THRESHOLD: 7048c2ecf20Sopenharmony_ci case DSM_VOL_ENA ... MAX98390_R24FF_REV_ID: 7058c2ecf20Sopenharmony_ci return true; 7068c2ecf20Sopenharmony_ci default: 7078c2ecf20Sopenharmony_ci return false; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci}; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_cistatic bool max98390_volatile_reg(struct device *dev, unsigned int reg) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci switch (reg) { 7148c2ecf20Sopenharmony_ci case MAX98390_SOFTWARE_RESET ... MAX98390_INT_EN3: 7158c2ecf20Sopenharmony_ci case MAX98390_MEAS_ADC_CH0_READ ... MAX98390_MEAS_ADC_CH2_READ: 7168c2ecf20Sopenharmony_ci case MAX98390_PWR_GATE_STATUS ... MAX98390_BROWNOUT_STATUS: 7178c2ecf20Sopenharmony_ci case MAX98390_BROWNOUT_LOWEST_STATUS: 7188c2ecf20Sopenharmony_ci case MAX98390_ENV_TRACK_BOOST_VOUT_READ: 7198c2ecf20Sopenharmony_ci case DSM_STBASS_HPF_B0_BYTE0 ... DSM_DEBUZZER_ATTACK_TIME_BYTE2: 7208c2ecf20Sopenharmony_ci case THERMAL_RDC_RD_BACK_BYTE1 ... DSMIG_DEBUZZER_THRESHOLD: 7218c2ecf20Sopenharmony_ci case DSM_THERMAL_GAIN ... DSM_WBDRC_GAIN: 7228c2ecf20Sopenharmony_ci return true; 7238c2ecf20Sopenharmony_ci default: 7248c2ecf20Sopenharmony_ci return false; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci#define MAX98390_RATES SNDRV_PCM_RATE_8000_48000 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci#define MAX98390_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 7318c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver max98390_dai[] = { 7348c2ecf20Sopenharmony_ci { 7358c2ecf20Sopenharmony_ci .name = "max98390-aif1", 7368c2ecf20Sopenharmony_ci .playback = { 7378c2ecf20Sopenharmony_ci .stream_name = "HiFi Playback", 7388c2ecf20Sopenharmony_ci .channels_min = 1, 7398c2ecf20Sopenharmony_ci .channels_max = 2, 7408c2ecf20Sopenharmony_ci .rates = MAX98390_RATES, 7418c2ecf20Sopenharmony_ci .formats = MAX98390_FORMATS, 7428c2ecf20Sopenharmony_ci }, 7438c2ecf20Sopenharmony_ci .capture = { 7448c2ecf20Sopenharmony_ci .stream_name = "HiFi Capture", 7458c2ecf20Sopenharmony_ci .channels_min = 1, 7468c2ecf20Sopenharmony_ci .channels_max = 2, 7478c2ecf20Sopenharmony_ci .rates = MAX98390_RATES, 7488c2ecf20Sopenharmony_ci .formats = MAX98390_FORMATS, 7498c2ecf20Sopenharmony_ci }, 7508c2ecf20Sopenharmony_ci .ops = &max98390_dai_ops, 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci}; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic int max98390_dsm_init(struct snd_soc_component *component) 7558c2ecf20Sopenharmony_ci{ 7568c2ecf20Sopenharmony_ci int ret; 7578c2ecf20Sopenharmony_ci int param_size, param_start_addr; 7588c2ecf20Sopenharmony_ci char filename[128]; 7598c2ecf20Sopenharmony_ci const char *vendor, *product; 7608c2ecf20Sopenharmony_ci struct max98390_priv *max98390 = 7618c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 7628c2ecf20Sopenharmony_ci const struct firmware *fw; 7638c2ecf20Sopenharmony_ci char *dsm_param; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci vendor = dmi_get_system_info(DMI_SYS_VENDOR); 7668c2ecf20Sopenharmony_ci product = dmi_get_system_info(DMI_PRODUCT_NAME); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (vendor && product) { 7698c2ecf20Sopenharmony_ci snprintf(filename, sizeof(filename), "dsm_param_%s_%s.bin", 7708c2ecf20Sopenharmony_ci vendor, product); 7718c2ecf20Sopenharmony_ci } else { 7728c2ecf20Sopenharmony_ci sprintf(filename, "dsm_param.bin"); 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci ret = request_firmware(&fw, filename, component->dev); 7758c2ecf20Sopenharmony_ci if (ret) { 7768c2ecf20Sopenharmony_ci ret = request_firmware(&fw, "dsm_param.bin", component->dev); 7778c2ecf20Sopenharmony_ci if (ret) 7788c2ecf20Sopenharmony_ci goto err; 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci dev_dbg(component->dev, 7828c2ecf20Sopenharmony_ci "max98390: param fw size %zd\n", 7838c2ecf20Sopenharmony_ci fw->size); 7848c2ecf20Sopenharmony_ci if (fw->size < MAX98390_DSM_PARAM_MIN_SIZE) { 7858c2ecf20Sopenharmony_ci dev_err(component->dev, 7868c2ecf20Sopenharmony_ci "param fw is invalid.\n"); 7878c2ecf20Sopenharmony_ci ret = -EINVAL; 7888c2ecf20Sopenharmony_ci goto err_alloc; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci dsm_param = (char *)fw->data; 7918c2ecf20Sopenharmony_ci param_start_addr = (dsm_param[0] & 0xff) | (dsm_param[1] & 0xff) << 8; 7928c2ecf20Sopenharmony_ci param_size = (dsm_param[2] & 0xff) | (dsm_param[3] & 0xff) << 8; 7938c2ecf20Sopenharmony_ci if (param_size > MAX98390_DSM_PARAM_MAX_SIZE || 7948c2ecf20Sopenharmony_ci param_start_addr < MAX98390_IRQ_CTRL || 7958c2ecf20Sopenharmony_ci fw->size < param_size + MAX98390_DSM_PAYLOAD_OFFSET) { 7968c2ecf20Sopenharmony_ci dev_err(component->dev, 7978c2ecf20Sopenharmony_ci "param fw is invalid.\n"); 7988c2ecf20Sopenharmony_ci ret = -EINVAL; 7998c2ecf20Sopenharmony_ci goto err_alloc; 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_R203A_AMP_EN, 0x80); 8028c2ecf20Sopenharmony_ci dsm_param += MAX98390_DSM_PAYLOAD_OFFSET; 8038c2ecf20Sopenharmony_ci regmap_bulk_write(max98390->regmap, param_start_addr, 8048c2ecf20Sopenharmony_ci dsm_param, param_size); 8058c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_R23E1_DSP_GLOBAL_EN, 0x01); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_cierr_alloc: 8088c2ecf20Sopenharmony_ci release_firmware(fw); 8098c2ecf20Sopenharmony_cierr: 8108c2ecf20Sopenharmony_ci return ret; 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic int max98390_dsm_calibrate(struct snd_soc_component *component) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci unsigned int rdc, rdc_cal_result, temp; 8168c2ecf20Sopenharmony_ci unsigned int rdc_integer, rdc_factor; 8178c2ecf20Sopenharmony_ci struct max98390_priv *max98390 = 8188c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_R203A_AMP_EN, 0x81); 8218c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, 0x01); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci regmap_read(max98390->regmap, 8248c2ecf20Sopenharmony_ci THERMAL_RDC_RD_BACK_BYTE1, &rdc); 8258c2ecf20Sopenharmony_ci regmap_read(max98390->regmap, 8268c2ecf20Sopenharmony_ci THERMAL_RDC_RD_BACK_BYTE0, &rdc_cal_result); 8278c2ecf20Sopenharmony_ci rdc_cal_result |= (rdc << 8) & 0x0000FFFF; 8288c2ecf20Sopenharmony_ci if (rdc_cal_result) 8298c2ecf20Sopenharmony_ci max98390->ref_rdc_value = 268435456U / rdc_cal_result; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci regmap_read(max98390->regmap, MAX98390_MEAS_ADC_CH2_READ, &temp); 8328c2ecf20Sopenharmony_ci max98390->ambient_temp_value = temp * 52 - 1188; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci rdc_integer = rdc_cal_result * 937 / 65536; 8358c2ecf20Sopenharmony_ci rdc_factor = ((rdc_cal_result * 937 * 100) / 65536) 8368c2ecf20Sopenharmony_ci - (rdc_integer * 100); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci dev_info(component->dev, "rdc resistance about %d.%02d ohm, reg=0x%X temp reg=0x%X\n", 8398c2ecf20Sopenharmony_ci rdc_integer, rdc_factor, rdc_cal_result, temp); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, 0x00); 8428c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_R203A_AMP_EN, 0x80); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci return 0; 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic void max98390_init_regs(struct snd_soc_component *component) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci struct max98390_priv *max98390 = 8508c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_CLK_MON, 0x6f); 8538c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_DAT_MON, 0x00); 8548c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_PWR_GATE_CTL, 0x00); 8558c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_PCM_RX_EN_A, 0x03); 8568c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_ENV_TRACK_VOUT_HEADROOM, 0x0e); 8578c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_BOOST_BYPASS1, 0x46); 8588c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_FET_SCALING3, 0x03); 8598c2ecf20Sopenharmony_ci} 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_cistatic int max98390_probe(struct snd_soc_component *component) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci struct max98390_priv *max98390 = 8648c2ecf20Sopenharmony_ci snd_soc_component_get_drvdata(component); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, MAX98390_SOFTWARE_RESET, 0x01); 8678c2ecf20Sopenharmony_ci /* Sleep reset settle time */ 8688c2ecf20Sopenharmony_ci msleep(20); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci /* Amp init setting */ 8718c2ecf20Sopenharmony_ci max98390_init_regs(component); 8728c2ecf20Sopenharmony_ci /* Update dsm bin param */ 8738c2ecf20Sopenharmony_ci max98390_dsm_init(component); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci /* Dsm Setting */ 8768c2ecf20Sopenharmony_ci if (max98390->ref_rdc_value) { 8778c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_RECIP_RDC_ROOM_BYTE0, 8788c2ecf20Sopenharmony_ci max98390->ref_rdc_value & 0x000000ff); 8798c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_RECIP_RDC_ROOM_BYTE1, 8808c2ecf20Sopenharmony_ci (max98390->ref_rdc_value >> 8) & 0x000000ff); 8818c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_RECIP_RDC_ROOM_BYTE2, 8828c2ecf20Sopenharmony_ci (max98390->ref_rdc_value >> 16) & 0x000000ff); 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci if (max98390->ambient_temp_value) { 8858c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_ROOM_TEMPERATURE_BYTE1, 8868c2ecf20Sopenharmony_ci (max98390->ambient_temp_value >> 8) & 0x000000ff); 8878c2ecf20Sopenharmony_ci regmap_write(max98390->regmap, DSM_TPROT_ROOM_TEMPERATURE_BYTE0, 8888c2ecf20Sopenharmony_ci (max98390->ambient_temp_value) & 0x000000ff); 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci return 0; 8928c2ecf20Sopenharmony_ci} 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 8958c2ecf20Sopenharmony_cistatic int max98390_suspend(struct device *dev) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci struct max98390_priv *max98390 = dev_get_drvdata(dev); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci dev_dbg(dev, "%s:Enter\n", __func__); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci regcache_cache_only(max98390->regmap, true); 9028c2ecf20Sopenharmony_ci regcache_mark_dirty(max98390->regmap); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci return 0; 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_cistatic int max98390_resume(struct device *dev) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci struct max98390_priv *max98390 = dev_get_drvdata(dev); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci dev_dbg(dev, "%s:Enter\n", __func__); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci regcache_cache_only(max98390->regmap, false); 9148c2ecf20Sopenharmony_ci regcache_sync(max98390->regmap); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci return 0; 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci#endif 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_cistatic const struct dev_pm_ops max98390_pm = { 9218c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(max98390_suspend, max98390_resume) 9228c2ecf20Sopenharmony_ci}; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver soc_codec_dev_max98390 = { 9258c2ecf20Sopenharmony_ci .probe = max98390_probe, 9268c2ecf20Sopenharmony_ci .controls = max98390_snd_controls, 9278c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(max98390_snd_controls), 9288c2ecf20Sopenharmony_ci .dapm_widgets = max98390_dapm_widgets, 9298c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(max98390_dapm_widgets), 9308c2ecf20Sopenharmony_ci .dapm_routes = max98390_audio_map, 9318c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(max98390_audio_map), 9328c2ecf20Sopenharmony_ci .idle_bias_on = 1, 9338c2ecf20Sopenharmony_ci .use_pmdown_time = 1, 9348c2ecf20Sopenharmony_ci .endianness = 1, 9358c2ecf20Sopenharmony_ci .non_legacy_dai_naming = 1, 9368c2ecf20Sopenharmony_ci}; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic const struct regmap_config max98390_regmap = { 9398c2ecf20Sopenharmony_ci .reg_bits = 16, 9408c2ecf20Sopenharmony_ci .val_bits = 8, 9418c2ecf20Sopenharmony_ci .max_register = MAX98390_R24FF_REV_ID, 9428c2ecf20Sopenharmony_ci .reg_defaults = max98390_reg_defaults, 9438c2ecf20Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(max98390_reg_defaults), 9448c2ecf20Sopenharmony_ci .readable_reg = max98390_readable_register, 9458c2ecf20Sopenharmony_ci .volatile_reg = max98390_volatile_reg, 9468c2ecf20Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 9478c2ecf20Sopenharmony_ci}; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_cistatic int max98390_i2c_probe(struct i2c_client *i2c, 9508c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci int ret = 0; 9538c2ecf20Sopenharmony_ci int reg = 0; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci struct max98390_priv *max98390 = NULL; 9568c2ecf20Sopenharmony_ci struct i2c_adapter *adapter = to_i2c_adapter(i2c->dev.parent); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci ret = i2c_check_functionality(adapter, 9598c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_BYTE 9608c2ecf20Sopenharmony_ci | I2C_FUNC_SMBUS_BYTE_DATA); 9618c2ecf20Sopenharmony_ci if (!ret) { 9628c2ecf20Sopenharmony_ci dev_err(&i2c->dev, "I2C check functionality failed\n"); 9638c2ecf20Sopenharmony_ci return -ENXIO; 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci max98390 = devm_kzalloc(&i2c->dev, sizeof(*max98390), GFP_KERNEL); 9678c2ecf20Sopenharmony_ci if (!max98390) { 9688c2ecf20Sopenharmony_ci ret = -ENOMEM; 9698c2ecf20Sopenharmony_ci return ret; 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci i2c_set_clientdata(i2c, max98390); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci ret = device_property_read_u32(&i2c->dev, "maxim,temperature_calib", 9748c2ecf20Sopenharmony_ci &max98390->ambient_temp_value); 9758c2ecf20Sopenharmony_ci if (ret) { 9768c2ecf20Sopenharmony_ci dev_info(&i2c->dev, 9778c2ecf20Sopenharmony_ci "no optional property 'temperature_calib' found, default:\n"); 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci ret = device_property_read_u32(&i2c->dev, "maxim,r0_calib", 9808c2ecf20Sopenharmony_ci &max98390->ref_rdc_value); 9818c2ecf20Sopenharmony_ci if (ret) { 9828c2ecf20Sopenharmony_ci dev_info(&i2c->dev, 9838c2ecf20Sopenharmony_ci "no optional property 'r0_calib' found, default:\n"); 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci dev_info(&i2c->dev, 9878c2ecf20Sopenharmony_ci "%s: r0_calib: 0x%x,temperature_calib: 0x%x", 9888c2ecf20Sopenharmony_ci __func__, max98390->ref_rdc_value, 9898c2ecf20Sopenharmony_ci max98390->ambient_temp_value); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci /* regmap initialization */ 9928c2ecf20Sopenharmony_ci max98390->regmap = devm_regmap_init_i2c(i2c, &max98390_regmap); 9938c2ecf20Sopenharmony_ci if (IS_ERR(max98390->regmap)) { 9948c2ecf20Sopenharmony_ci ret = PTR_ERR(max98390->regmap); 9958c2ecf20Sopenharmony_ci dev_err(&i2c->dev, 9968c2ecf20Sopenharmony_ci "Failed to allocate regmap: %d\n", ret); 9978c2ecf20Sopenharmony_ci return ret; 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci /* Check Revision ID */ 10018c2ecf20Sopenharmony_ci ret = regmap_read(max98390->regmap, 10028c2ecf20Sopenharmony_ci MAX98390_R24FF_REV_ID, ®); 10038c2ecf20Sopenharmony_ci if (ret) { 10048c2ecf20Sopenharmony_ci dev_err(&i2c->dev, 10058c2ecf20Sopenharmony_ci "ret=%d, Failed to read: 0x%02X\n", 10068c2ecf20Sopenharmony_ci ret, MAX98390_R24FF_REV_ID); 10078c2ecf20Sopenharmony_ci return ret; 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci dev_info(&i2c->dev, "MAX98390 revisionID: 0x%02X\n", reg); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(&i2c->dev, 10128c2ecf20Sopenharmony_ci &soc_codec_dev_max98390, 10138c2ecf20Sopenharmony_ci max98390_dai, ARRAY_SIZE(max98390_dai)); 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci return ret; 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cistatic const struct i2c_device_id max98390_i2c_id[] = { 10198c2ecf20Sopenharmony_ci { "max98390", 0}, 10208c2ecf20Sopenharmony_ci {}, 10218c2ecf20Sopenharmony_ci}; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, max98390_i2c_id); 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci#if defined(CONFIG_OF) 10268c2ecf20Sopenharmony_cistatic const struct of_device_id max98390_of_match[] = { 10278c2ecf20Sopenharmony_ci { .compatible = "maxim,max98390", }, 10288c2ecf20Sopenharmony_ci {} 10298c2ecf20Sopenharmony_ci}; 10308c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, max98390_of_match); 10318c2ecf20Sopenharmony_ci#endif 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 10348c2ecf20Sopenharmony_cistatic const struct acpi_device_id max98390_acpi_match[] = { 10358c2ecf20Sopenharmony_ci { "MX98390", 0 }, 10368c2ecf20Sopenharmony_ci {}, 10378c2ecf20Sopenharmony_ci}; 10388c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, max98390_acpi_match); 10398c2ecf20Sopenharmony_ci#endif 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_cistatic struct i2c_driver max98390_i2c_driver = { 10428c2ecf20Sopenharmony_ci .driver = { 10438c2ecf20Sopenharmony_ci .name = "max98390", 10448c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(max98390_of_match), 10458c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(max98390_acpi_match), 10468c2ecf20Sopenharmony_ci .pm = &max98390_pm, 10478c2ecf20Sopenharmony_ci }, 10488c2ecf20Sopenharmony_ci .probe = max98390_i2c_probe, 10498c2ecf20Sopenharmony_ci .id_table = max98390_i2c_id, 10508c2ecf20Sopenharmony_ci}; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_cimodule_i2c_driver(max98390_i2c_driver) 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ALSA SoC MAX98390 driver"); 10558c2ecf20Sopenharmony_ciMODULE_AUTHOR("Steve Lee <steves.lee@maximintegrated.com>"); 10568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1057