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, &reg);
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