162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci// Copyright (c) 2022, Analog Devices Inc. 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/module.h> 562306a36Sopenharmony_ci#include <linux/pm_runtime.h> 662306a36Sopenharmony_ci#include <linux/regmap.h> 762306a36Sopenharmony_ci#include <linux/soundwire/sdw.h> 862306a36Sopenharmony_ci#include <linux/soundwire/sdw_registers.h> 962306a36Sopenharmony_ci#include <linux/soundwire/sdw_type.h> 1062306a36Sopenharmony_ci#include <sound/pcm.h> 1162306a36Sopenharmony_ci#include <sound/pcm_params.h> 1262306a36Sopenharmony_ci#include <sound/soc.h> 1362306a36Sopenharmony_ci#include <sound/tlv.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "max98363.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic struct reg_default max98363_reg[] = { 1862306a36Sopenharmony_ci {MAX98363_R2021_ERR_MON_CTRL, 0x0}, 1962306a36Sopenharmony_ci {MAX98363_R2022_SPK_MON_THRESH, 0x0}, 2062306a36Sopenharmony_ci {MAX98363_R2023_SPK_MON_DURATION, 0x0}, 2162306a36Sopenharmony_ci {MAX98363_R2030_TONE_GEN_CFG, 0x0}, 2262306a36Sopenharmony_ci {MAX98363_R203F_TONE_GEN_EN, 0x0}, 2362306a36Sopenharmony_ci {MAX98363_R2040_AMP_VOL, 0x0}, 2462306a36Sopenharmony_ci {MAX98363_R2041_AMP_GAIN, 0x5}, 2562306a36Sopenharmony_ci {MAX98363_R2042_DSP_CFG, 0x0}, 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic bool max98363_readable_register(struct device *dev, unsigned int reg) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci switch (reg) { 3162306a36Sopenharmony_ci case MAX98363_R2001_INTR_RAW: 3262306a36Sopenharmony_ci case MAX98363_R2003_INTR_STATE: 3362306a36Sopenharmony_ci case MAX98363_R2005_INTR_FALG: 3462306a36Sopenharmony_ci case MAX98363_R2007_INTR_EN: 3562306a36Sopenharmony_ci case MAX98363_R2009_INTR_CLR: 3662306a36Sopenharmony_ci case MAX98363_R2021_ERR_MON_CTRL ... MAX98363_R2023_SPK_MON_DURATION: 3762306a36Sopenharmony_ci case MAX98363_R2030_TONE_GEN_CFG: 3862306a36Sopenharmony_ci case MAX98363_R203F_TONE_GEN_EN: 3962306a36Sopenharmony_ci case MAX98363_R2040_AMP_VOL: 4062306a36Sopenharmony_ci case MAX98363_R2041_AMP_GAIN: 4162306a36Sopenharmony_ci case MAX98363_R2042_DSP_CFG: 4262306a36Sopenharmony_ci case MAX98363_R21FF_REV_ID: 4362306a36Sopenharmony_ci return true; 4462306a36Sopenharmony_ci default: 4562306a36Sopenharmony_ci return false; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic bool max98363_volatile_reg(struct device *dev, unsigned int reg) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci switch (reg) { 5262306a36Sopenharmony_ci case MAX98363_R2001_INTR_RAW: 5362306a36Sopenharmony_ci case MAX98363_R2003_INTR_STATE: 5462306a36Sopenharmony_ci case MAX98363_R2005_INTR_FALG: 5562306a36Sopenharmony_ci case MAX98363_R2007_INTR_EN: 5662306a36Sopenharmony_ci case MAX98363_R2009_INTR_CLR: 5762306a36Sopenharmony_ci case MAX98363_R21FF_REV_ID: 5862306a36Sopenharmony_ci return true; 5962306a36Sopenharmony_ci default: 6062306a36Sopenharmony_ci return false; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic const struct regmap_config max98363_sdw_regmap = { 6562306a36Sopenharmony_ci .reg_bits = 32, 6662306a36Sopenharmony_ci .val_bits = 8, 6762306a36Sopenharmony_ci .max_register = MAX98363_R21FF_REV_ID, 6862306a36Sopenharmony_ci .reg_defaults = max98363_reg, 6962306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(max98363_reg), 7062306a36Sopenharmony_ci .readable_reg = max98363_readable_register, 7162306a36Sopenharmony_ci .volatile_reg = max98363_volatile_reg, 7262306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 7362306a36Sopenharmony_ci .use_single_read = true, 7462306a36Sopenharmony_ci .use_single_write = true, 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic int max98363_suspend(struct device *dev) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct max98363_priv *max98363 = dev_get_drvdata(dev); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci regcache_cache_only(max98363->regmap, true); 8262306a36Sopenharmony_ci regcache_mark_dirty(max98363->regmap); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci return 0; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#define MAX98363_PROBE_TIMEOUT 5000 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic int max98363_resume(struct device *dev) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct sdw_slave *slave = dev_to_sdw_dev(dev); 9262306a36Sopenharmony_ci struct max98363_priv *max98363 = dev_get_drvdata(dev); 9362306a36Sopenharmony_ci unsigned long time; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (!max98363->first_hw_init) 9662306a36Sopenharmony_ci return 0; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (!slave->unattach_request) 9962306a36Sopenharmony_ci goto regmap_sync; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci time = wait_for_completion_timeout(&slave->initialization_complete, 10262306a36Sopenharmony_ci msecs_to_jiffies(MAX98363_PROBE_TIMEOUT)); 10362306a36Sopenharmony_ci if (!time) { 10462306a36Sopenharmony_ci dev_err(dev, "Initialization not complete, timed out\n"); 10562306a36Sopenharmony_ci return -ETIMEDOUT; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ciregmap_sync: 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci slave->unattach_request = 0; 11162306a36Sopenharmony_ci regcache_cache_only(max98363->regmap, false); 11262306a36Sopenharmony_ci regcache_sync(max98363->regmap); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return 0; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic DEFINE_RUNTIME_DEV_PM_OPS(max98363_pm, max98363_suspend, max98363_resume, NULL); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic int max98363_read_prop(struct sdw_slave *slave) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci struct sdw_slave_prop *prop = &slave->prop; 12262306a36Sopenharmony_ci int nval, i; 12362306a36Sopenharmony_ci u32 bit; 12462306a36Sopenharmony_ci unsigned long addr; 12562306a36Sopenharmony_ci struct sdw_dpn_prop *dpn; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* BITMAP: 00000010 Dataport 1 is active */ 13062306a36Sopenharmony_ci prop->sink_ports = BIT(1); 13162306a36Sopenharmony_ci prop->paging_support = true; 13262306a36Sopenharmony_ci prop->clk_stop_timeout = 20; 13362306a36Sopenharmony_ci prop->simple_clk_stop_capable = true; 13462306a36Sopenharmony_ci prop->clock_reg_supported = true; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci nval = hweight32(prop->sink_ports); 13762306a36Sopenharmony_ci prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, 13862306a36Sopenharmony_ci sizeof(*prop->sink_dpn_prop), 13962306a36Sopenharmony_ci GFP_KERNEL); 14062306a36Sopenharmony_ci if (!prop->sink_dpn_prop) 14162306a36Sopenharmony_ci return -ENOMEM; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci i = 0; 14462306a36Sopenharmony_ci dpn = prop->sink_dpn_prop; 14562306a36Sopenharmony_ci addr = prop->sink_ports; 14662306a36Sopenharmony_ci for_each_set_bit(bit, &addr, 32) { 14762306a36Sopenharmony_ci dpn[i].num = bit; 14862306a36Sopenharmony_ci dpn[i].type = SDW_DPN_FULL; 14962306a36Sopenharmony_ci dpn[i].simple_ch_prep_sm = true; 15062306a36Sopenharmony_ci dpn[i].ch_prep_timeout = 10; 15162306a36Sopenharmony_ci i++; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return 0; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic int max98363_io_init(struct sdw_slave *slave) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci struct device *dev = &slave->dev; 16062306a36Sopenharmony_ci struct max98363_priv *max98363 = dev_get_drvdata(dev); 16162306a36Sopenharmony_ci int ret, reg; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci regcache_cache_only(max98363->regmap, false); 16462306a36Sopenharmony_ci if (max98363->first_hw_init) 16562306a36Sopenharmony_ci regcache_cache_bypass(max98363->regmap, true); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* 16862306a36Sopenharmony_ci * PM runtime status is marked as 'active' only when a Slave reports as Attached 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_ci if (!max98363->first_hw_init) 17162306a36Sopenharmony_ci /* update count of parent 'active' children */ 17262306a36Sopenharmony_ci pm_runtime_set_active(dev); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci pm_runtime_get_noresume(dev); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci ret = regmap_read(max98363->regmap, MAX98363_R21FF_REV_ID, ®); 17762306a36Sopenharmony_ci if (!ret) 17862306a36Sopenharmony_ci dev_info(dev, "Revision ID: %X\n", reg); 17962306a36Sopenharmony_ci else 18062306a36Sopenharmony_ci goto out; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (max98363->first_hw_init) { 18362306a36Sopenharmony_ci regcache_cache_bypass(max98363->regmap, false); 18462306a36Sopenharmony_ci regcache_mark_dirty(max98363->regmap); 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci max98363->first_hw_init = true; 18862306a36Sopenharmony_ci max98363->hw_init = true; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ciout: 19162306a36Sopenharmony_ci pm_runtime_mark_last_busy(dev); 19262306a36Sopenharmony_ci pm_runtime_put_autosuspend(dev); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return ret; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci#define MAX98363_RATES SNDRV_PCM_RATE_8000_192000 19862306a36Sopenharmony_ci#define MAX98363_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic int max98363_sdw_dai_hw_params(struct snd_pcm_substream *substream, 20162306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 20262306a36Sopenharmony_ci struct snd_soc_dai *dai) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 20562306a36Sopenharmony_ci struct max98363_priv *max98363 = 20662306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci struct sdw_stream_config stream_config; 20962306a36Sopenharmony_ci struct sdw_port_config port_config; 21062306a36Sopenharmony_ci enum sdw_data_direction direction; 21162306a36Sopenharmony_ci struct sdw_stream_runtime *stream; 21262306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci int ret; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci stream = snd_soc_dai_get_dma_data(dai, substream); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (!stream) 21962306a36Sopenharmony_ci return -EINVAL; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (!max98363->slave) 22262306a36Sopenharmony_ci return -EINVAL; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) 22562306a36Sopenharmony_ci return -EINVAL; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci direction = SDW_DATA_DIR_RX; 22862306a36Sopenharmony_ci port_config.num = 1; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci stream_config.frame_rate = params_rate(params); 23162306a36Sopenharmony_ci stream_config.bps = snd_pcm_format_width(params_format(params)); 23262306a36Sopenharmony_ci stream_config.direction = direction; 23362306a36Sopenharmony_ci stream_config.ch_count = 1; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (stream_config.ch_count > runtime->hw.channels_max) { 23662306a36Sopenharmony_ci stream_config.ch_count = runtime->hw.channels_max; 23762306a36Sopenharmony_ci dev_info(dai->dev, "Number of channels: %d (requested: %d)\n", 23862306a36Sopenharmony_ci stream_config.ch_count, params_channels(params)); 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci port_config.ch_mask = GENMASK((int)stream_config.ch_count - 1, 0); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci ret = sdw_stream_add_slave(max98363->slave, &stream_config, 24362306a36Sopenharmony_ci &port_config, 1, stream); 24462306a36Sopenharmony_ci if (ret) { 24562306a36Sopenharmony_ci dev_err(dai->dev, "Unable to configure port\n"); 24662306a36Sopenharmony_ci return ret; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci dev_dbg(component->dev, "Format supported %d", params_format(params)); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return 0; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic int max98363_pcm_hw_free(struct snd_pcm_substream *substream, 25562306a36Sopenharmony_ci struct snd_soc_dai *dai) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 25862306a36Sopenharmony_ci struct max98363_priv *max98363 = 25962306a36Sopenharmony_ci snd_soc_component_get_drvdata(component); 26062306a36Sopenharmony_ci struct sdw_stream_runtime *stream = 26162306a36Sopenharmony_ci snd_soc_dai_get_dma_data(dai, substream); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (!max98363->slave) 26462306a36Sopenharmony_ci return -EINVAL; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci sdw_stream_remove_slave(max98363->slave, stream); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci return 0; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic int max98363_set_sdw_stream(struct snd_soc_dai *dai, 27262306a36Sopenharmony_ci void *sdw_stream, int direction) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci snd_soc_dai_dma_data_set(dai, direction, sdw_stream); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci return 0; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic const struct snd_soc_dai_ops max98363_dai_sdw_ops = { 28062306a36Sopenharmony_ci .hw_params = max98363_sdw_dai_hw_params, 28162306a36Sopenharmony_ci .hw_free = max98363_pcm_hw_free, 28262306a36Sopenharmony_ci .set_stream = max98363_set_sdw_stream, 28362306a36Sopenharmony_ci}; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic struct snd_soc_dai_driver max98363_dai[] = { 28662306a36Sopenharmony_ci { 28762306a36Sopenharmony_ci .name = "max98363-aif1", 28862306a36Sopenharmony_ci .playback = { 28962306a36Sopenharmony_ci .stream_name = "HiFi Playback", 29062306a36Sopenharmony_ci .channels_min = 1, 29162306a36Sopenharmony_ci .channels_max = 1, 29262306a36Sopenharmony_ci .rates = MAX98363_RATES, 29362306a36Sopenharmony_ci .formats = MAX98363_FORMATS, 29462306a36Sopenharmony_ci }, 29562306a36Sopenharmony_ci .ops = &max98363_dai_sdw_ops, 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci}; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int max98363_update_status(struct sdw_slave *slave, 30062306a36Sopenharmony_ci enum sdw_slave_status status) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci struct max98363_priv *max98363 = dev_get_drvdata(&slave->dev); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (status == SDW_SLAVE_UNATTACHED) 30562306a36Sopenharmony_ci max98363->hw_init = false; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* 30862306a36Sopenharmony_ci * Perform initialization only if slave status is SDW_SLAVE_ATTACHED 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_ci if (max98363->hw_init || status != SDW_SLAVE_ATTACHED) 31162306a36Sopenharmony_ci return 0; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* perform I/O transfers required for Slave initialization */ 31462306a36Sopenharmony_ci return max98363_io_init(slave); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic struct sdw_slave_ops max98363_slave_ops = { 31862306a36Sopenharmony_ci .read_prop = max98363_read_prop, 31962306a36Sopenharmony_ci .update_status = max98363_update_status, 32062306a36Sopenharmony_ci}; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic DECLARE_TLV_DB_SCALE(max98363_digital_tlv, -6350, 50, 1); 32362306a36Sopenharmony_cistatic const DECLARE_TLV_DB_RANGE(max98363_spk_tlv, 32462306a36Sopenharmony_ci 0, 5, TLV_DB_SCALE_ITEM(-300, 300, 0), 32562306a36Sopenharmony_ci); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic const char * const max98363_tone_cfg_text[] = { 32862306a36Sopenharmony_ci "Reserved", "0", "+FS/2", "-FS/2", "1KHz", 32962306a36Sopenharmony_ci "12KHz", "8KHz", "6KHz", "4KHz", "3KHz", 33062306a36Sopenharmony_ci "2KHz", "1.5KHz", "Reserved", "500Hz", "250Hz" 33162306a36Sopenharmony_ci}; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(max98363_tone_cfg_enum, 33462306a36Sopenharmony_ci MAX98363_R2030_TONE_GEN_CFG, 0, 33562306a36Sopenharmony_ci max98363_tone_cfg_text); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic const char * const max98363_spkmon_duration_text[] = { 33862306a36Sopenharmony_ci "8ms", "20ms", "40ms", "60ms", 33962306a36Sopenharmony_ci "80ms", "160ms", "240ms", "320ms", 34062306a36Sopenharmony_ci "400ms", "480ms", "560ms", "640ms", 34162306a36Sopenharmony_ci "720ms", "800ms", "880ms", "960ms" 34262306a36Sopenharmony_ci}; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(max98363_spkmon_duration_enum, 34562306a36Sopenharmony_ci MAX98363_R2023_SPK_MON_DURATION, 0, 34662306a36Sopenharmony_ci max98363_spkmon_duration_text); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic const struct snd_kcontrol_new max98363_snd_controls[] = { 34962306a36Sopenharmony_ci SOC_SINGLE_TLV("Digital Volume", MAX98363_R2040_AMP_VOL, 35062306a36Sopenharmony_ci 0, 0x7F, 1, max98363_digital_tlv), 35162306a36Sopenharmony_ci SOC_SINGLE_TLV("Speaker Volume", MAX98363_R2041_AMP_GAIN, 35262306a36Sopenharmony_ci 0, 10, 0, max98363_spk_tlv), 35362306a36Sopenharmony_ci SOC_SINGLE("Tone Generator Switch", MAX98363_R203F_TONE_GEN_EN, 35462306a36Sopenharmony_ci 0, 1, 0), 35562306a36Sopenharmony_ci SOC_ENUM("Tone Config", max98363_tone_cfg_enum), 35662306a36Sopenharmony_ci SOC_SINGLE("Ramp Switch", MAX98363_R2042_DSP_CFG, 35762306a36Sopenharmony_ci MAX98363_AMP_DSP_CFG_RMP_SHIFT, 1, 0), 35862306a36Sopenharmony_ci SOC_SINGLE("CLK Monitor Switch", MAX98363_R2021_ERR_MON_CTRL, 35962306a36Sopenharmony_ci MAX98363_CLOCK_MON_SHIFT, 1, 0), 36062306a36Sopenharmony_ci SOC_SINGLE("SPKMON Monitor Switch", MAX98363_R2021_ERR_MON_CTRL, 36162306a36Sopenharmony_ci MAX98363_SPKMON_SHIFT, 1, 0), 36262306a36Sopenharmony_ci SOC_SINGLE("SPKMON Thresh", MAX98363_R2022_SPK_MON_THRESH, 0, 0xFF, 0), 36362306a36Sopenharmony_ci SOC_ENUM("SPKMON Duration", max98363_spkmon_duration_enum), 36462306a36Sopenharmony_ci}; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget max98363_dapm_widgets[] = { 36762306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("AIFIN", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), 36862306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("BE_OUT"), 36962306a36Sopenharmony_ci}; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic const struct snd_soc_dapm_route max98363_audio_map[] = { 37262306a36Sopenharmony_ci /* Plabyack */ 37362306a36Sopenharmony_ci {"BE_OUT", NULL, "AIFIN"}, 37462306a36Sopenharmony_ci}; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_codec_dev_max98363 = { 37762306a36Sopenharmony_ci .controls = max98363_snd_controls, 37862306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(max98363_snd_controls), 37962306a36Sopenharmony_ci .dapm_widgets = max98363_dapm_widgets, 38062306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(max98363_dapm_widgets), 38162306a36Sopenharmony_ci .dapm_routes = max98363_audio_map, 38262306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(max98363_audio_map), 38362306a36Sopenharmony_ci .use_pmdown_time = 1, 38462306a36Sopenharmony_ci .endianness = 1, 38562306a36Sopenharmony_ci}; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic int max98363_init(struct sdw_slave *slave, struct regmap *regmap) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci struct max98363_priv *max98363; 39062306a36Sopenharmony_ci int ret; 39162306a36Sopenharmony_ci struct device *dev = &slave->dev; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* Allocate and assign private driver data structure */ 39462306a36Sopenharmony_ci max98363 = devm_kzalloc(dev, sizeof(*max98363), GFP_KERNEL); 39562306a36Sopenharmony_ci if (!max98363) 39662306a36Sopenharmony_ci return -ENOMEM; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci dev_set_drvdata(dev, max98363); 39962306a36Sopenharmony_ci max98363->regmap = regmap; 40062306a36Sopenharmony_ci max98363->slave = slave; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci regcache_cache_only(max98363->regmap, true); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci max98363->hw_init = false; 40562306a36Sopenharmony_ci max98363->first_hw_init = false; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* codec registration */ 40862306a36Sopenharmony_ci ret = devm_snd_soc_register_component(dev, &soc_codec_dev_max98363, 40962306a36Sopenharmony_ci max98363_dai, 41062306a36Sopenharmony_ci ARRAY_SIZE(max98363_dai)); 41162306a36Sopenharmony_ci if (ret < 0) { 41262306a36Sopenharmony_ci dev_err(dev, "Failed to register codec: %d\n", ret); 41362306a36Sopenharmony_ci return ret; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* set autosuspend parameters */ 41762306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, 3000); 41862306a36Sopenharmony_ci pm_runtime_use_autosuspend(dev); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* make sure the device does not suspend immediately */ 42162306a36Sopenharmony_ci pm_runtime_mark_last_busy(dev); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci pm_runtime_enable(dev); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* important note: the device is NOT tagged as 'active' and will remain 42662306a36Sopenharmony_ci * 'suspended' until the hardware is enumerated/initialized. This is required 42762306a36Sopenharmony_ci * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently 42862306a36Sopenharmony_ci * fail with -EACCESS because of race conditions between card creation and enumeration 42962306a36Sopenharmony_ci */ 43062306a36Sopenharmony_ci return 0; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic int max98363_sdw_probe(struct sdw_slave *slave, 43462306a36Sopenharmony_ci const struct sdw_device_id *id) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci struct regmap *regmap; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* Regmap Initialization */ 43962306a36Sopenharmony_ci regmap = devm_regmap_init_sdw(slave, &max98363_sdw_regmap); 44062306a36Sopenharmony_ci if (IS_ERR(regmap)) 44162306a36Sopenharmony_ci return PTR_ERR(regmap); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci return max98363_init(slave, regmap); 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic const struct sdw_device_id max98363_id[] = { 44762306a36Sopenharmony_ci SDW_SLAVE_ENTRY(0x019F, 0x8363, 0), 44862306a36Sopenharmony_ci {}, 44962306a36Sopenharmony_ci}; 45062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(sdw, max98363_id); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic struct sdw_driver max98363_sdw_driver = { 45362306a36Sopenharmony_ci .driver = { 45462306a36Sopenharmony_ci .name = "max98363", 45562306a36Sopenharmony_ci .pm = pm_ptr(&max98363_pm), 45662306a36Sopenharmony_ci }, 45762306a36Sopenharmony_ci .probe = max98363_sdw_probe, 45862306a36Sopenharmony_ci .ops = &max98363_slave_ops, 45962306a36Sopenharmony_ci .id_table = max98363_id, 46062306a36Sopenharmony_ci}; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cimodule_sdw_driver(max98363_sdw_driver); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC MAX98363 driver SDW"); 46562306a36Sopenharmony_ciMODULE_AUTHOR("Ryan Lee <ryans.lee@analog.com>"); 46662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 467