162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * lpass-cpu.c -- ALSA SoC CPU DAI driver for QTi LPASS
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/clk.h>
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/of.h>
1262306a36Sopenharmony_ci#include <linux/of_device.h>
1362306a36Sopenharmony_ci#include <linux/platform_device.h>
1462306a36Sopenharmony_ci#include <sound/pcm.h>
1562306a36Sopenharmony_ci#include <sound/pcm_params.h>
1662306a36Sopenharmony_ci#include <linux/regmap.h>
1762306a36Sopenharmony_ci#include <sound/soc.h>
1862306a36Sopenharmony_ci#include <sound/soc-dai.h>
1962306a36Sopenharmony_ci#include "lpass-lpaif-reg.h"
2062306a36Sopenharmony_ci#include "lpass.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define LPASS_CPU_MAX_MI2S_LINES	4
2362306a36Sopenharmony_ci#define LPASS_CPU_I2S_SD0_MASK		BIT(0)
2462306a36Sopenharmony_ci#define LPASS_CPU_I2S_SD1_MASK		BIT(1)
2562306a36Sopenharmony_ci#define LPASS_CPU_I2S_SD2_MASK		BIT(2)
2662306a36Sopenharmony_ci#define LPASS_CPU_I2S_SD3_MASK		BIT(3)
2762306a36Sopenharmony_ci#define LPASS_CPU_I2S_SD0_1_MASK	GENMASK(1, 0)
2862306a36Sopenharmony_ci#define LPASS_CPU_I2S_SD2_3_MASK	GENMASK(3, 2)
2962306a36Sopenharmony_ci#define LPASS_CPU_I2S_SD0_1_2_MASK	GENMASK(2, 0)
3062306a36Sopenharmony_ci#define LPASS_CPU_I2S_SD0_1_2_3_MASK	GENMASK(3, 0)
3162306a36Sopenharmony_ci#define LPASS_REG_READ 1
3262306a36Sopenharmony_ci#define LPASS_REG_WRITE 0
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/*
3562306a36Sopenharmony_ci * Channel maps for Quad channel playbacks on MI2S Secondary
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_cistatic struct snd_pcm_chmap_elem lpass_quad_chmaps[] = {
3862306a36Sopenharmony_ci		{ .channels = 4,
3962306a36Sopenharmony_ci		  .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_RL,
4062306a36Sopenharmony_ci				SNDRV_CHMAP_FR, SNDRV_CHMAP_RR } },
4162306a36Sopenharmony_ci		{ }
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_cistatic int lpass_cpu_init_i2sctl_bitfields(struct device *dev,
4462306a36Sopenharmony_ci			struct lpaif_i2sctl *i2sctl, struct regmap *map)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	struct lpass_data *drvdata = dev_get_drvdata(dev);
4762306a36Sopenharmony_ci	struct lpass_variant *v = drvdata->variant;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	i2sctl->loopback = devm_regmap_field_alloc(dev, map, v->loopback);
5062306a36Sopenharmony_ci	i2sctl->spken = devm_regmap_field_alloc(dev, map, v->spken);
5162306a36Sopenharmony_ci	i2sctl->spkmode = devm_regmap_field_alloc(dev, map, v->spkmode);
5262306a36Sopenharmony_ci	i2sctl->spkmono = devm_regmap_field_alloc(dev, map, v->spkmono);
5362306a36Sopenharmony_ci	i2sctl->micen = devm_regmap_field_alloc(dev, map, v->micen);
5462306a36Sopenharmony_ci	i2sctl->micmode = devm_regmap_field_alloc(dev, map, v->micmode);
5562306a36Sopenharmony_ci	i2sctl->micmono = devm_regmap_field_alloc(dev, map, v->micmono);
5662306a36Sopenharmony_ci	i2sctl->wssrc = devm_regmap_field_alloc(dev, map, v->wssrc);
5762306a36Sopenharmony_ci	i2sctl->bitwidth = devm_regmap_field_alloc(dev, map, v->bitwidth);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (IS_ERR(i2sctl->loopback) || IS_ERR(i2sctl->spken) ||
6062306a36Sopenharmony_ci	    IS_ERR(i2sctl->spkmode) || IS_ERR(i2sctl->spkmono) ||
6162306a36Sopenharmony_ci	    IS_ERR(i2sctl->micen) || IS_ERR(i2sctl->micmode) ||
6262306a36Sopenharmony_ci	    IS_ERR(i2sctl->micmono) || IS_ERR(i2sctl->wssrc) ||
6362306a36Sopenharmony_ci	    IS_ERR(i2sctl->bitwidth))
6462306a36Sopenharmony_ci		return -EINVAL;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	return 0;
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
7062306a36Sopenharmony_ci		unsigned int freq, int dir)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
7362306a36Sopenharmony_ci	int ret;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq);
7662306a36Sopenharmony_ci	if (ret)
7762306a36Sopenharmony_ci		dev_err(dai->dev, "error setting mi2s osrclk to %u: %d\n",
7862306a36Sopenharmony_ci			freq, ret);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	return ret;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream,
8462306a36Sopenharmony_ci		struct snd_soc_dai *dai)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
8762306a36Sopenharmony_ci	int ret;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	ret = clk_prepare_enable(drvdata->mi2s_osr_clk[dai->driver->id]);
9062306a36Sopenharmony_ci	if (ret) {
9162306a36Sopenharmony_ci		dev_err(dai->dev, "error in enabling mi2s osr clk: %d\n", ret);
9262306a36Sopenharmony_ci		return ret;
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci	ret = clk_prepare(drvdata->mi2s_bit_clk[dai->driver->id]);
9562306a36Sopenharmony_ci	if (ret) {
9662306a36Sopenharmony_ci		dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret);
9762306a36Sopenharmony_ci		clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
9862306a36Sopenharmony_ci		return ret;
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci	return 0;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
10462306a36Sopenharmony_ci		struct snd_soc_dai *dai)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
10762306a36Sopenharmony_ci	struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
10862306a36Sopenharmony_ci	unsigned int id = dai->driver->id;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
11162306a36Sopenharmony_ci	/*
11262306a36Sopenharmony_ci	 * Ensure LRCLK is disabled even in device node validation.
11362306a36Sopenharmony_ci	 * Will not impact if disabled in lpass_cpu_daiops_trigger()
11462306a36Sopenharmony_ci	 * suspend.
11562306a36Sopenharmony_ci	 */
11662306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
11762306a36Sopenharmony_ci		regmap_fields_write(i2sctl->spken, id, LPAIF_I2SCTL_SPKEN_DISABLE);
11862306a36Sopenharmony_ci	else
11962306a36Sopenharmony_ci		regmap_fields_write(i2sctl->micen, id, LPAIF_I2SCTL_MICEN_DISABLE);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	/*
12262306a36Sopenharmony_ci	 * BCLK may not be enabled if lpass_cpu_daiops_prepare is called before
12362306a36Sopenharmony_ci	 * lpass_cpu_daiops_shutdown. It's paired with the clk_enable in
12462306a36Sopenharmony_ci	 * lpass_cpu_daiops_prepare.
12562306a36Sopenharmony_ci	 */
12662306a36Sopenharmony_ci	if (drvdata->mi2s_was_prepared[dai->driver->id]) {
12762306a36Sopenharmony_ci		drvdata->mi2s_was_prepared[dai->driver->id] = false;
12862306a36Sopenharmony_ci		clk_disable(drvdata->mi2s_bit_clk[dai->driver->id]);
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	clk_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
13562306a36Sopenharmony_ci		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
13862306a36Sopenharmony_ci	struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
13962306a36Sopenharmony_ci	unsigned int id = dai->driver->id;
14062306a36Sopenharmony_ci	snd_pcm_format_t format = params_format(params);
14162306a36Sopenharmony_ci	unsigned int channels = params_channels(params);
14262306a36Sopenharmony_ci	unsigned int rate = params_rate(params);
14362306a36Sopenharmony_ci	unsigned int mode;
14462306a36Sopenharmony_ci	unsigned int regval;
14562306a36Sopenharmony_ci	int bitwidth, ret;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	bitwidth = snd_pcm_format_width(format);
14862306a36Sopenharmony_ci	if (bitwidth < 0) {
14962306a36Sopenharmony_ci		dev_err(dai->dev, "invalid bit width given: %d\n", bitwidth);
15062306a36Sopenharmony_ci		return bitwidth;
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	ret = regmap_fields_write(i2sctl->loopback, id,
15462306a36Sopenharmony_ci				 LPAIF_I2SCTL_LOOPBACK_DISABLE);
15562306a36Sopenharmony_ci	if (ret) {
15662306a36Sopenharmony_ci		dev_err(dai->dev, "error updating loopback field: %d\n", ret);
15762306a36Sopenharmony_ci		return ret;
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	ret = regmap_fields_write(i2sctl->wssrc, id,
16162306a36Sopenharmony_ci				 LPAIF_I2SCTL_WSSRC_INTERNAL);
16262306a36Sopenharmony_ci	if (ret) {
16362306a36Sopenharmony_ci		dev_err(dai->dev, "error updating wssrc field: %d\n", ret);
16462306a36Sopenharmony_ci		return ret;
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	switch (bitwidth) {
16862306a36Sopenharmony_ci	case 16:
16962306a36Sopenharmony_ci		regval = LPAIF_I2SCTL_BITWIDTH_16;
17062306a36Sopenharmony_ci		break;
17162306a36Sopenharmony_ci	case 24:
17262306a36Sopenharmony_ci		regval = LPAIF_I2SCTL_BITWIDTH_24;
17362306a36Sopenharmony_ci		break;
17462306a36Sopenharmony_ci	case 32:
17562306a36Sopenharmony_ci		regval = LPAIF_I2SCTL_BITWIDTH_32;
17662306a36Sopenharmony_ci		break;
17762306a36Sopenharmony_ci	default:
17862306a36Sopenharmony_ci		dev_err(dai->dev, "invalid bitwidth given: %d\n", bitwidth);
17962306a36Sopenharmony_ci		return -EINVAL;
18062306a36Sopenharmony_ci	}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	ret = regmap_fields_write(i2sctl->bitwidth, id, regval);
18362306a36Sopenharmony_ci	if (ret) {
18462306a36Sopenharmony_ci		dev_err(dai->dev, "error updating bitwidth field: %d\n", ret);
18562306a36Sopenharmony_ci		return ret;
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
18962306a36Sopenharmony_ci		mode = drvdata->mi2s_playback_sd_mode[id];
19062306a36Sopenharmony_ci	else
19162306a36Sopenharmony_ci		mode = drvdata->mi2s_capture_sd_mode[id];
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	if (!mode) {
19462306a36Sopenharmony_ci		dev_err(dai->dev, "no line is assigned\n");
19562306a36Sopenharmony_ci		return -EINVAL;
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	switch (channels) {
19962306a36Sopenharmony_ci	case 1:
20062306a36Sopenharmony_ci	case 2:
20162306a36Sopenharmony_ci		switch (mode) {
20262306a36Sopenharmony_ci		case LPAIF_I2SCTL_MODE_QUAD01:
20362306a36Sopenharmony_ci		case LPAIF_I2SCTL_MODE_6CH:
20462306a36Sopenharmony_ci		case LPAIF_I2SCTL_MODE_8CH:
20562306a36Sopenharmony_ci			mode = LPAIF_I2SCTL_MODE_SD0;
20662306a36Sopenharmony_ci			break;
20762306a36Sopenharmony_ci		case LPAIF_I2SCTL_MODE_QUAD23:
20862306a36Sopenharmony_ci			mode = LPAIF_I2SCTL_MODE_SD2;
20962306a36Sopenharmony_ci			break;
21062306a36Sopenharmony_ci		}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci		break;
21362306a36Sopenharmony_ci	case 4:
21462306a36Sopenharmony_ci		if (mode < LPAIF_I2SCTL_MODE_QUAD01) {
21562306a36Sopenharmony_ci			dev_err(dai->dev, "cannot configure 4 channels with mode %d\n",
21662306a36Sopenharmony_ci				mode);
21762306a36Sopenharmony_ci			return -EINVAL;
21862306a36Sopenharmony_ci		}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci		switch (mode) {
22162306a36Sopenharmony_ci		case LPAIF_I2SCTL_MODE_6CH:
22262306a36Sopenharmony_ci		case LPAIF_I2SCTL_MODE_8CH:
22362306a36Sopenharmony_ci			mode = LPAIF_I2SCTL_MODE_QUAD01;
22462306a36Sopenharmony_ci			break;
22562306a36Sopenharmony_ci		}
22662306a36Sopenharmony_ci		break;
22762306a36Sopenharmony_ci	case 6:
22862306a36Sopenharmony_ci		if (mode < LPAIF_I2SCTL_MODE_6CH) {
22962306a36Sopenharmony_ci			dev_err(dai->dev, "cannot configure 6 channels with mode %d\n",
23062306a36Sopenharmony_ci				mode);
23162306a36Sopenharmony_ci			return -EINVAL;
23262306a36Sopenharmony_ci		}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci		switch (mode) {
23562306a36Sopenharmony_ci		case LPAIF_I2SCTL_MODE_8CH:
23662306a36Sopenharmony_ci			mode = LPAIF_I2SCTL_MODE_6CH;
23762306a36Sopenharmony_ci			break;
23862306a36Sopenharmony_ci		}
23962306a36Sopenharmony_ci		break;
24062306a36Sopenharmony_ci	case 8:
24162306a36Sopenharmony_ci		if (mode < LPAIF_I2SCTL_MODE_8CH) {
24262306a36Sopenharmony_ci			dev_err(dai->dev, "cannot configure 8 channels with mode %d\n",
24362306a36Sopenharmony_ci				mode);
24462306a36Sopenharmony_ci			return -EINVAL;
24562306a36Sopenharmony_ci		}
24662306a36Sopenharmony_ci		break;
24762306a36Sopenharmony_ci	default:
24862306a36Sopenharmony_ci		dev_err(dai->dev, "invalid channels given: %u\n", channels);
24962306a36Sopenharmony_ci		return -EINVAL;
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
25362306a36Sopenharmony_ci		ret = regmap_fields_write(i2sctl->spkmode, id,
25462306a36Sopenharmony_ci					 LPAIF_I2SCTL_SPKMODE(mode));
25562306a36Sopenharmony_ci		if (ret) {
25662306a36Sopenharmony_ci			dev_err(dai->dev, "error writing to i2sctl spkr mode: %d\n",
25762306a36Sopenharmony_ci				ret);
25862306a36Sopenharmony_ci			return ret;
25962306a36Sopenharmony_ci		}
26062306a36Sopenharmony_ci		if (channels >= 2)
26162306a36Sopenharmony_ci			ret = regmap_fields_write(i2sctl->spkmono, id,
26262306a36Sopenharmony_ci						 LPAIF_I2SCTL_SPKMONO_STEREO);
26362306a36Sopenharmony_ci		else
26462306a36Sopenharmony_ci			ret = regmap_fields_write(i2sctl->spkmono, id,
26562306a36Sopenharmony_ci						 LPAIF_I2SCTL_SPKMONO_MONO);
26662306a36Sopenharmony_ci	} else {
26762306a36Sopenharmony_ci		ret = regmap_fields_write(i2sctl->micmode, id,
26862306a36Sopenharmony_ci					 LPAIF_I2SCTL_MICMODE(mode));
26962306a36Sopenharmony_ci		if (ret) {
27062306a36Sopenharmony_ci			dev_err(dai->dev, "error writing to i2sctl mic mode: %d\n",
27162306a36Sopenharmony_ci				ret);
27262306a36Sopenharmony_ci			return ret;
27362306a36Sopenharmony_ci		}
27462306a36Sopenharmony_ci		if (channels >= 2)
27562306a36Sopenharmony_ci			ret = regmap_fields_write(i2sctl->micmono, id,
27662306a36Sopenharmony_ci						 LPAIF_I2SCTL_MICMONO_STEREO);
27762306a36Sopenharmony_ci		else
27862306a36Sopenharmony_ci			ret = regmap_fields_write(i2sctl->micmono, id,
27962306a36Sopenharmony_ci						 LPAIF_I2SCTL_MICMONO_MONO);
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	if (ret) {
28362306a36Sopenharmony_ci		dev_err(dai->dev, "error writing to i2sctl channels mode: %d\n",
28462306a36Sopenharmony_ci			ret);
28562306a36Sopenharmony_ci		return ret;
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	ret = clk_set_rate(drvdata->mi2s_bit_clk[id],
28962306a36Sopenharmony_ci			   rate * bitwidth * 2);
29062306a36Sopenharmony_ci	if (ret) {
29162306a36Sopenharmony_ci		dev_err(dai->dev, "error setting mi2s bitclk to %u: %d\n",
29262306a36Sopenharmony_ci			rate * bitwidth * 2, ret);
29362306a36Sopenharmony_ci		return ret;
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	return 0;
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
30062306a36Sopenharmony_ci		int cmd, struct snd_soc_dai *dai)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
30362306a36Sopenharmony_ci	struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
30462306a36Sopenharmony_ci	unsigned int id = dai->driver->id;
30562306a36Sopenharmony_ci	int ret = -EINVAL;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	switch (cmd) {
30862306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
30962306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
31062306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
31162306a36Sopenharmony_ci		/*
31262306a36Sopenharmony_ci		 * Ensure lpass BCLK/LRCLK is enabled during
31362306a36Sopenharmony_ci		 * device resume as lpass_cpu_daiops_prepare() is not called
31462306a36Sopenharmony_ci		 * after the device resumes. We don't check mi2s_was_prepared before
31562306a36Sopenharmony_ci		 * enable/disable BCLK in trigger events because:
31662306a36Sopenharmony_ci		 *  1. These trigger events are paired, so the BCLK
31762306a36Sopenharmony_ci		 *     enable_count is balanced.
31862306a36Sopenharmony_ci		 *  2. the BCLK can be shared (ex: headset and headset mic),
31962306a36Sopenharmony_ci		 *     we need to increase the enable_count so that we don't
32062306a36Sopenharmony_ci		 *     turn off the shared BCLK while other devices are using
32162306a36Sopenharmony_ci		 *     it.
32262306a36Sopenharmony_ci		 */
32362306a36Sopenharmony_ci		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
32462306a36Sopenharmony_ci			ret = regmap_fields_write(i2sctl->spken, id,
32562306a36Sopenharmony_ci						 LPAIF_I2SCTL_SPKEN_ENABLE);
32662306a36Sopenharmony_ci		} else  {
32762306a36Sopenharmony_ci			ret = regmap_fields_write(i2sctl->micen, id,
32862306a36Sopenharmony_ci						 LPAIF_I2SCTL_MICEN_ENABLE);
32962306a36Sopenharmony_ci		}
33062306a36Sopenharmony_ci		if (ret)
33162306a36Sopenharmony_ci			dev_err(dai->dev, "error writing to i2sctl reg: %d\n",
33262306a36Sopenharmony_ci				ret);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci		ret = clk_enable(drvdata->mi2s_bit_clk[id]);
33562306a36Sopenharmony_ci		if (ret) {
33662306a36Sopenharmony_ci			dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret);
33762306a36Sopenharmony_ci			clk_disable(drvdata->mi2s_osr_clk[id]);
33862306a36Sopenharmony_ci			return ret;
33962306a36Sopenharmony_ci		}
34062306a36Sopenharmony_ci		break;
34162306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
34262306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
34362306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
34462306a36Sopenharmony_ci		/*
34562306a36Sopenharmony_ci		 * To ensure lpass BCLK/LRCLK is disabled during
34662306a36Sopenharmony_ci		 * device suspend.
34762306a36Sopenharmony_ci		 */
34862306a36Sopenharmony_ci		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
34962306a36Sopenharmony_ci			ret = regmap_fields_write(i2sctl->spken, id,
35062306a36Sopenharmony_ci						 LPAIF_I2SCTL_SPKEN_DISABLE);
35162306a36Sopenharmony_ci		} else  {
35262306a36Sopenharmony_ci			ret = regmap_fields_write(i2sctl->micen, id,
35362306a36Sopenharmony_ci						 LPAIF_I2SCTL_MICEN_DISABLE);
35462306a36Sopenharmony_ci		}
35562306a36Sopenharmony_ci		if (ret)
35662306a36Sopenharmony_ci			dev_err(dai->dev, "error writing to i2sctl reg: %d\n",
35762306a36Sopenharmony_ci				ret);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci		clk_disable(drvdata->mi2s_bit_clk[dai->driver->id]);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci		break;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	return ret;
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
36862306a36Sopenharmony_ci		struct snd_soc_dai *dai)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
37162306a36Sopenharmony_ci	struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
37262306a36Sopenharmony_ci	unsigned int id = dai->driver->id;
37362306a36Sopenharmony_ci	int ret;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	/*
37662306a36Sopenharmony_ci	 * Ensure lpass BCLK/LRCLK is enabled bit before playback/capture
37762306a36Sopenharmony_ci	 * data flow starts. This allows other codec to have some delay before
37862306a36Sopenharmony_ci	 * the data flow.
37962306a36Sopenharmony_ci	 * (ex: to drop start up pop noise before capture starts).
38062306a36Sopenharmony_ci	 */
38162306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
38262306a36Sopenharmony_ci		ret = regmap_fields_write(i2sctl->spken, id, LPAIF_I2SCTL_SPKEN_ENABLE);
38362306a36Sopenharmony_ci	else
38462306a36Sopenharmony_ci		ret = regmap_fields_write(i2sctl->micen, id, LPAIF_I2SCTL_MICEN_ENABLE);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	if (ret) {
38762306a36Sopenharmony_ci		dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
38862306a36Sopenharmony_ci		return ret;
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/*
39262306a36Sopenharmony_ci	 * Check mi2s_was_prepared before enabling BCLK as lpass_cpu_daiops_prepare can
39362306a36Sopenharmony_ci	 * be called multiple times. It's paired with the clk_disable in
39462306a36Sopenharmony_ci	 * lpass_cpu_daiops_shutdown.
39562306a36Sopenharmony_ci	 */
39662306a36Sopenharmony_ci	if (!drvdata->mi2s_was_prepared[dai->driver->id]) {
39762306a36Sopenharmony_ci		ret = clk_enable(drvdata->mi2s_bit_clk[id]);
39862306a36Sopenharmony_ci		if (ret) {
39962306a36Sopenharmony_ci			dev_err(dai->dev, "error in enabling mi2s bit clk: %d\n", ret);
40062306a36Sopenharmony_ci			return ret;
40162306a36Sopenharmony_ci		}
40262306a36Sopenharmony_ci		drvdata->mi2s_was_prepared[dai->driver->id] = true;
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci	return 0;
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic int lpass_cpu_daiops_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	int ret;
41062306a36Sopenharmony_ci	struct snd_soc_dai_driver *drv = dai->driver;
41162306a36Sopenharmony_ci	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (drvdata->mi2s_playback_sd_mode[dai->id] == LPAIF_I2SCTL_MODE_QUAD01) {
41462306a36Sopenharmony_ci		ret =  snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK,
41562306a36Sopenharmony_ci				lpass_quad_chmaps, drv->playback.channels_max, 0,
41662306a36Sopenharmony_ci				NULL);
41762306a36Sopenharmony_ci		if (ret < 0)
41862306a36Sopenharmony_ci			return ret;
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	return 0;
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic int lpass_cpu_daiops_probe(struct snd_soc_dai *dai)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
42762306a36Sopenharmony_ci	int ret;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	/* ensure audio hardware is disabled */
43062306a36Sopenharmony_ci	ret = regmap_write(drvdata->lpaif_map,
43162306a36Sopenharmony_ci			LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0);
43262306a36Sopenharmony_ci	if (ret)
43362306a36Sopenharmony_ci		dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	return ret;
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ciconst struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
43962306a36Sopenharmony_ci	.probe		= lpass_cpu_daiops_probe,
44062306a36Sopenharmony_ci	.set_sysclk	= lpass_cpu_daiops_set_sysclk,
44162306a36Sopenharmony_ci	.startup	= lpass_cpu_daiops_startup,
44262306a36Sopenharmony_ci	.shutdown	= lpass_cpu_daiops_shutdown,
44362306a36Sopenharmony_ci	.hw_params	= lpass_cpu_daiops_hw_params,
44462306a36Sopenharmony_ci	.trigger	= lpass_cpu_daiops_trigger,
44562306a36Sopenharmony_ci	.prepare	= lpass_cpu_daiops_prepare,
44662306a36Sopenharmony_ci};
44762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ciconst struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops2 = {
45062306a36Sopenharmony_ci	.pcm_new	= lpass_cpu_daiops_pcm_new,
45162306a36Sopenharmony_ci	.probe		= lpass_cpu_daiops_probe,
45262306a36Sopenharmony_ci	.set_sysclk	= lpass_cpu_daiops_set_sysclk,
45362306a36Sopenharmony_ci	.startup	= lpass_cpu_daiops_startup,
45462306a36Sopenharmony_ci	.shutdown	= lpass_cpu_daiops_shutdown,
45562306a36Sopenharmony_ci	.hw_params	= lpass_cpu_daiops_hw_params,
45662306a36Sopenharmony_ci	.trigger	= lpass_cpu_daiops_trigger,
45762306a36Sopenharmony_ci	.prepare	= lpass_cpu_daiops_prepare,
45862306a36Sopenharmony_ci};
45962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops2);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic int asoc_qcom_of_xlate_dai_name(struct snd_soc_component *component,
46262306a36Sopenharmony_ci				   const struct of_phandle_args *args,
46362306a36Sopenharmony_ci				   const char **dai_name)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
46662306a36Sopenharmony_ci	struct lpass_variant *variant = drvdata->variant;
46762306a36Sopenharmony_ci	int id = args->args[0];
46862306a36Sopenharmony_ci	int ret = -EINVAL;
46962306a36Sopenharmony_ci	int i;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	for (i = 0; i  < variant->num_dai; i++) {
47262306a36Sopenharmony_ci		if (variant->dai_driver[i].id == id) {
47362306a36Sopenharmony_ci			*dai_name = variant->dai_driver[i].name;
47462306a36Sopenharmony_ci			ret = 0;
47562306a36Sopenharmony_ci			break;
47662306a36Sopenharmony_ci		}
47762306a36Sopenharmony_ci	}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	return ret;
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic const struct snd_soc_component_driver lpass_cpu_comp_driver = {
48362306a36Sopenharmony_ci	.name = "lpass-cpu",
48462306a36Sopenharmony_ci	.of_xlate_dai_name = asoc_qcom_of_xlate_dai_name,
48562306a36Sopenharmony_ci	.legacy_dai_naming = 1,
48662306a36Sopenharmony_ci};
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_cistatic bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	struct lpass_data *drvdata = dev_get_drvdata(dev);
49162306a36Sopenharmony_ci	struct lpass_variant *v = drvdata->variant;
49262306a36Sopenharmony_ci	int i;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	for (i = 0; i < v->i2s_ports; ++i)
49562306a36Sopenharmony_ci		if (reg == LPAIF_I2SCTL_REG(v, i))
49662306a36Sopenharmony_ci			return true;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	for (i = 0; i < v->irq_ports; ++i) {
49962306a36Sopenharmony_ci		if (reg == LPAIF_IRQEN_REG(v, i))
50062306a36Sopenharmony_ci			return true;
50162306a36Sopenharmony_ci		if (reg == LPAIF_IRQCLEAR_REG(v, i))
50262306a36Sopenharmony_ci			return true;
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	for (i = 0; i < v->rdma_channels; ++i) {
50662306a36Sopenharmony_ci		if (reg == LPAIF_RDMACTL_REG(v, i))
50762306a36Sopenharmony_ci			return true;
50862306a36Sopenharmony_ci		if (reg == LPAIF_RDMABASE_REG(v, i))
50962306a36Sopenharmony_ci			return true;
51062306a36Sopenharmony_ci		if (reg == LPAIF_RDMABUFF_REG(v, i))
51162306a36Sopenharmony_ci			return true;
51262306a36Sopenharmony_ci		if (reg == LPAIF_RDMAPER_REG(v, i))
51362306a36Sopenharmony_ci			return true;
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	for (i = 0; i < v->wrdma_channels; ++i) {
51762306a36Sopenharmony_ci		if (reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start))
51862306a36Sopenharmony_ci			return true;
51962306a36Sopenharmony_ci		if (reg == LPAIF_WRDMABASE_REG(v, i + v->wrdma_channel_start))
52062306a36Sopenharmony_ci			return true;
52162306a36Sopenharmony_ci		if (reg == LPAIF_WRDMABUFF_REG(v, i + v->wrdma_channel_start))
52262306a36Sopenharmony_ci			return true;
52362306a36Sopenharmony_ci		if (reg == LPAIF_WRDMAPER_REG(v, i + v->wrdma_channel_start))
52462306a36Sopenharmony_ci			return true;
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	return false;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	struct lpass_data *drvdata = dev_get_drvdata(dev);
53362306a36Sopenharmony_ci	struct lpass_variant *v = drvdata->variant;
53462306a36Sopenharmony_ci	int i;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	for (i = 0; i < v->i2s_ports; ++i)
53762306a36Sopenharmony_ci		if (reg == LPAIF_I2SCTL_REG(v, i))
53862306a36Sopenharmony_ci			return true;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	for (i = 0; i < v->irq_ports; ++i) {
54162306a36Sopenharmony_ci		if (reg == LPAIF_IRQCLEAR_REG(v, i))
54262306a36Sopenharmony_ci			return true;
54362306a36Sopenharmony_ci		if (reg == LPAIF_IRQEN_REG(v, i))
54462306a36Sopenharmony_ci			return true;
54562306a36Sopenharmony_ci		if (reg == LPAIF_IRQSTAT_REG(v, i))
54662306a36Sopenharmony_ci			return true;
54762306a36Sopenharmony_ci	}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	for (i = 0; i < v->rdma_channels; ++i) {
55062306a36Sopenharmony_ci		if (reg == LPAIF_RDMACTL_REG(v, i))
55162306a36Sopenharmony_ci			return true;
55262306a36Sopenharmony_ci		if (reg == LPAIF_RDMABASE_REG(v, i))
55362306a36Sopenharmony_ci			return true;
55462306a36Sopenharmony_ci		if (reg == LPAIF_RDMABUFF_REG(v, i))
55562306a36Sopenharmony_ci			return true;
55662306a36Sopenharmony_ci		if (reg == LPAIF_RDMACURR_REG(v, i))
55762306a36Sopenharmony_ci			return true;
55862306a36Sopenharmony_ci		if (reg == LPAIF_RDMAPER_REG(v, i))
55962306a36Sopenharmony_ci			return true;
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	for (i = 0; i < v->wrdma_channels; ++i) {
56362306a36Sopenharmony_ci		if (reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start))
56462306a36Sopenharmony_ci			return true;
56562306a36Sopenharmony_ci		if (reg == LPAIF_WRDMABASE_REG(v, i + v->wrdma_channel_start))
56662306a36Sopenharmony_ci			return true;
56762306a36Sopenharmony_ci		if (reg == LPAIF_WRDMABUFF_REG(v, i + v->wrdma_channel_start))
56862306a36Sopenharmony_ci			return true;
56962306a36Sopenharmony_ci		if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start))
57062306a36Sopenharmony_ci			return true;
57162306a36Sopenharmony_ci		if (reg == LPAIF_WRDMAPER_REG(v, i + v->wrdma_channel_start))
57262306a36Sopenharmony_ci			return true;
57362306a36Sopenharmony_ci	}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	return false;
57662306a36Sopenharmony_ci}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_cistatic bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	struct lpass_data *drvdata = dev_get_drvdata(dev);
58162306a36Sopenharmony_ci	struct lpass_variant *v = drvdata->variant;
58262306a36Sopenharmony_ci	int i;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	for (i = 0; i < v->irq_ports; ++i) {
58562306a36Sopenharmony_ci		if (reg == LPAIF_IRQCLEAR_REG(v, i))
58662306a36Sopenharmony_ci			return true;
58762306a36Sopenharmony_ci		if (reg == LPAIF_IRQSTAT_REG(v, i))
58862306a36Sopenharmony_ci			return true;
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	for (i = 0; i < v->rdma_channels; ++i)
59262306a36Sopenharmony_ci		if (reg == LPAIF_RDMACURR_REG(v, i))
59362306a36Sopenharmony_ci			return true;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	for (i = 0; i < v->wrdma_channels; ++i)
59662306a36Sopenharmony_ci		if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start))
59762306a36Sopenharmony_ci			return true;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	return false;
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_cistatic struct regmap_config lpass_cpu_regmap_config = {
60362306a36Sopenharmony_ci	.name = "lpass_cpu",
60462306a36Sopenharmony_ci	.reg_bits = 32,
60562306a36Sopenharmony_ci	.reg_stride = 4,
60662306a36Sopenharmony_ci	.val_bits = 32,
60762306a36Sopenharmony_ci	.writeable_reg = lpass_cpu_regmap_writeable,
60862306a36Sopenharmony_ci	.readable_reg = lpass_cpu_regmap_readable,
60962306a36Sopenharmony_ci	.volatile_reg = lpass_cpu_regmap_volatile,
61062306a36Sopenharmony_ci	.cache_type = REGCACHE_FLAT,
61162306a36Sopenharmony_ci};
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_cistatic int lpass_hdmi_init_bitfields(struct device *dev, struct regmap *map)
61462306a36Sopenharmony_ci{
61562306a36Sopenharmony_ci	struct lpass_data *drvdata = dev_get_drvdata(dev);
61662306a36Sopenharmony_ci	struct lpass_variant *v = drvdata->variant;
61762306a36Sopenharmony_ci	unsigned int i;
61862306a36Sopenharmony_ci	struct lpass_hdmi_tx_ctl *tx_ctl;
61962306a36Sopenharmony_ci	struct regmap_field *legacy_en;
62062306a36Sopenharmony_ci	struct lpass_vbit_ctrl *vbit_ctl;
62162306a36Sopenharmony_ci	struct regmap_field *tx_parity;
62262306a36Sopenharmony_ci	struct lpass_dp_metadata_ctl *meta_ctl;
62362306a36Sopenharmony_ci	struct lpass_sstream_ctl *sstream_ctl;
62462306a36Sopenharmony_ci	struct regmap_field *ch_msb;
62562306a36Sopenharmony_ci	struct regmap_field *ch_lsb;
62662306a36Sopenharmony_ci	struct lpass_hdmitx_dmactl *tx_dmactl;
62762306a36Sopenharmony_ci	int rval;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	tx_ctl = devm_kzalloc(dev, sizeof(*tx_ctl), GFP_KERNEL);
63062306a36Sopenharmony_ci	if (!tx_ctl)
63162306a36Sopenharmony_ci		return -ENOMEM;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	QCOM_REGMAP_FIELD_ALLOC(dev, map, v->soft_reset, tx_ctl->soft_reset);
63462306a36Sopenharmony_ci	QCOM_REGMAP_FIELD_ALLOC(dev, map, v->force_reset, tx_ctl->force_reset);
63562306a36Sopenharmony_ci	drvdata->tx_ctl = tx_ctl;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	QCOM_REGMAP_FIELD_ALLOC(dev, map, v->legacy_en, legacy_en);
63862306a36Sopenharmony_ci	drvdata->hdmitx_legacy_en = legacy_en;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	vbit_ctl = devm_kzalloc(dev, sizeof(*vbit_ctl), GFP_KERNEL);
64162306a36Sopenharmony_ci	if (!vbit_ctl)
64262306a36Sopenharmony_ci		return -ENOMEM;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	QCOM_REGMAP_FIELD_ALLOC(dev, map, v->replace_vbit, vbit_ctl->replace_vbit);
64562306a36Sopenharmony_ci	QCOM_REGMAP_FIELD_ALLOC(dev, map, v->vbit_stream, vbit_ctl->vbit_stream);
64662306a36Sopenharmony_ci	drvdata->vbit_ctl = vbit_ctl;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	QCOM_REGMAP_FIELD_ALLOC(dev, map, v->calc_en, tx_parity);
65062306a36Sopenharmony_ci	drvdata->hdmitx_parity_calc_en = tx_parity;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	meta_ctl = devm_kzalloc(dev, sizeof(*meta_ctl), GFP_KERNEL);
65362306a36Sopenharmony_ci	if (!meta_ctl)
65462306a36Sopenharmony_ci		return -ENOMEM;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	rval = devm_regmap_field_bulk_alloc(dev, map, &meta_ctl->mute, &v->mute, 7);
65762306a36Sopenharmony_ci	if (rval)
65862306a36Sopenharmony_ci		return rval;
65962306a36Sopenharmony_ci	drvdata->meta_ctl = meta_ctl;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	sstream_ctl = devm_kzalloc(dev, sizeof(*sstream_ctl), GFP_KERNEL);
66262306a36Sopenharmony_ci	if (!sstream_ctl)
66362306a36Sopenharmony_ci		return -ENOMEM;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	rval = devm_regmap_field_bulk_alloc(dev, map, &sstream_ctl->sstream_en, &v->sstream_en, 9);
66662306a36Sopenharmony_ci	if (rval)
66762306a36Sopenharmony_ci		return rval;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	drvdata->sstream_ctl = sstream_ctl;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	for (i = 0; i < LPASS_MAX_HDMI_DMA_CHANNELS; i++) {
67262306a36Sopenharmony_ci		QCOM_REGMAP_FIELD_ALLOC(dev, map, v->msb_bits, ch_msb);
67362306a36Sopenharmony_ci		drvdata->hdmitx_ch_msb[i] = ch_msb;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci		QCOM_REGMAP_FIELD_ALLOC(dev, map, v->lsb_bits, ch_lsb);
67662306a36Sopenharmony_ci		drvdata->hdmitx_ch_lsb[i] = ch_lsb;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci		tx_dmactl = devm_kzalloc(dev, sizeof(*tx_dmactl), GFP_KERNEL);
67962306a36Sopenharmony_ci		if (!tx_dmactl)
68062306a36Sopenharmony_ci			return -ENOMEM;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci		QCOM_REGMAP_FIELD_ALLOC(dev, map, v->use_hw_chs, tx_dmactl->use_hw_chs);
68362306a36Sopenharmony_ci		QCOM_REGMAP_FIELD_ALLOC(dev, map, v->use_hw_usr, tx_dmactl->use_hw_usr);
68462306a36Sopenharmony_ci		QCOM_REGMAP_FIELD_ALLOC(dev, map, v->hw_chs_sel, tx_dmactl->hw_chs_sel);
68562306a36Sopenharmony_ci		QCOM_REGMAP_FIELD_ALLOC(dev, map, v->hw_usr_sel, tx_dmactl->hw_usr_sel);
68662306a36Sopenharmony_ci		drvdata->hdmi_tx_dmactl[i] = tx_dmactl;
68762306a36Sopenharmony_ci	}
68862306a36Sopenharmony_ci	return 0;
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_cistatic bool lpass_hdmi_regmap_writeable(struct device *dev, unsigned int reg)
69262306a36Sopenharmony_ci{
69362306a36Sopenharmony_ci	struct lpass_data *drvdata = dev_get_drvdata(dev);
69462306a36Sopenharmony_ci	struct lpass_variant *v = drvdata->variant;
69562306a36Sopenharmony_ci	int i;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	if (reg == LPASS_HDMI_TX_CTL_ADDR(v))
69862306a36Sopenharmony_ci		return true;
69962306a36Sopenharmony_ci	if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
70062306a36Sopenharmony_ci		return true;
70162306a36Sopenharmony_ci	if (reg == LPASS_HDMI_TX_VBIT_CTL_ADDR(v))
70262306a36Sopenharmony_ci		return true;
70362306a36Sopenharmony_ci	if (reg == LPASS_HDMI_TX_PARITY_ADDR(v))
70462306a36Sopenharmony_ci		return true;
70562306a36Sopenharmony_ci	if (reg == LPASS_HDMI_TX_DP_ADDR(v))
70662306a36Sopenharmony_ci		return true;
70762306a36Sopenharmony_ci	if (reg == LPASS_HDMI_TX_SSTREAM_ADDR(v))
70862306a36Sopenharmony_ci		return true;
70962306a36Sopenharmony_ci	if (reg == LPASS_HDMITX_APP_IRQEN_REG(v))
71062306a36Sopenharmony_ci		return true;
71162306a36Sopenharmony_ci	if (reg == LPASS_HDMITX_APP_IRQCLEAR_REG(v))
71262306a36Sopenharmony_ci		return true;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	for (i = 0; i < v->hdmi_rdma_channels; i++) {
71562306a36Sopenharmony_ci		if (reg == LPASS_HDMI_TX_CH_LSB_ADDR(v, i))
71662306a36Sopenharmony_ci			return true;
71762306a36Sopenharmony_ci		if (reg == LPASS_HDMI_TX_CH_MSB_ADDR(v, i))
71862306a36Sopenharmony_ci			return true;
71962306a36Sopenharmony_ci		if (reg == LPASS_HDMI_TX_DMA_ADDR(v, i))
72062306a36Sopenharmony_ci			return true;
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	for (i = 0; i < v->hdmi_rdma_channels; ++i) {
72462306a36Sopenharmony_ci		if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
72562306a36Sopenharmony_ci			return true;
72662306a36Sopenharmony_ci		if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
72762306a36Sopenharmony_ci			return true;
72862306a36Sopenharmony_ci		if (reg == LPAIF_HDMI_RDMABUFF_REG(v, i))
72962306a36Sopenharmony_ci			return true;
73062306a36Sopenharmony_ci		if (reg == LPAIF_HDMI_RDMAPER_REG(v, i))
73162306a36Sopenharmony_ci			return true;
73262306a36Sopenharmony_ci	}
73362306a36Sopenharmony_ci	return false;
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_cistatic bool lpass_hdmi_regmap_readable(struct device *dev, unsigned int reg)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	struct lpass_data *drvdata = dev_get_drvdata(dev);
73962306a36Sopenharmony_ci	struct lpass_variant *v = drvdata->variant;
74062306a36Sopenharmony_ci	int i;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	if (reg == LPASS_HDMI_TX_CTL_ADDR(v))
74362306a36Sopenharmony_ci		return true;
74462306a36Sopenharmony_ci	if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
74562306a36Sopenharmony_ci		return true;
74662306a36Sopenharmony_ci	if (reg == LPASS_HDMI_TX_VBIT_CTL_ADDR(v))
74762306a36Sopenharmony_ci		return true;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	for (i = 0; i < v->hdmi_rdma_channels; i++) {
75062306a36Sopenharmony_ci		if (reg == LPASS_HDMI_TX_CH_LSB_ADDR(v, i))
75162306a36Sopenharmony_ci			return true;
75262306a36Sopenharmony_ci		if (reg == LPASS_HDMI_TX_CH_MSB_ADDR(v, i))
75362306a36Sopenharmony_ci			return true;
75462306a36Sopenharmony_ci		if (reg == LPASS_HDMI_TX_DMA_ADDR(v, i))
75562306a36Sopenharmony_ci			return true;
75662306a36Sopenharmony_ci	}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	if (reg == LPASS_HDMI_TX_PARITY_ADDR(v))
75962306a36Sopenharmony_ci		return true;
76062306a36Sopenharmony_ci	if (reg == LPASS_HDMI_TX_DP_ADDR(v))
76162306a36Sopenharmony_ci		return true;
76262306a36Sopenharmony_ci	if (reg == LPASS_HDMI_TX_SSTREAM_ADDR(v))
76362306a36Sopenharmony_ci		return true;
76462306a36Sopenharmony_ci	if (reg == LPASS_HDMITX_APP_IRQEN_REG(v))
76562306a36Sopenharmony_ci		return true;
76662306a36Sopenharmony_ci	if (reg == LPASS_HDMITX_APP_IRQSTAT_REG(v))
76762306a36Sopenharmony_ci		return true;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	for (i = 0; i < v->hdmi_rdma_channels; ++i) {
77062306a36Sopenharmony_ci		if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
77162306a36Sopenharmony_ci			return true;
77262306a36Sopenharmony_ci		if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
77362306a36Sopenharmony_ci			return true;
77462306a36Sopenharmony_ci		if (reg == LPAIF_HDMI_RDMABUFF_REG(v, i))
77562306a36Sopenharmony_ci			return true;
77662306a36Sopenharmony_ci		if (reg == LPAIF_HDMI_RDMAPER_REG(v, i))
77762306a36Sopenharmony_ci			return true;
77862306a36Sopenharmony_ci		if (reg == LPAIF_HDMI_RDMACURR_REG(v, i))
77962306a36Sopenharmony_ci			return true;
78062306a36Sopenharmony_ci	}
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	return false;
78362306a36Sopenharmony_ci}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_cistatic bool lpass_hdmi_regmap_volatile(struct device *dev, unsigned int reg)
78662306a36Sopenharmony_ci{
78762306a36Sopenharmony_ci	struct lpass_data *drvdata = dev_get_drvdata(dev);
78862306a36Sopenharmony_ci	struct lpass_variant *v = drvdata->variant;
78962306a36Sopenharmony_ci	int i;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	if (reg == LPASS_HDMITX_APP_IRQSTAT_REG(v))
79262306a36Sopenharmony_ci		return true;
79362306a36Sopenharmony_ci	if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
79462306a36Sopenharmony_ci		return true;
79562306a36Sopenharmony_ci	if (reg == LPASS_HDMI_TX_VBIT_CTL_ADDR(v))
79662306a36Sopenharmony_ci		return true;
79762306a36Sopenharmony_ci	if (reg == LPASS_HDMI_TX_PARITY_ADDR(v))
79862306a36Sopenharmony_ci		return true;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	for (i = 0; i < v->hdmi_rdma_channels; ++i) {
80162306a36Sopenharmony_ci		if (reg == LPAIF_HDMI_RDMACURR_REG(v, i))
80262306a36Sopenharmony_ci			return true;
80362306a36Sopenharmony_ci		if (reg == LPASS_HDMI_TX_DMA_ADDR(v, i))
80462306a36Sopenharmony_ci			return true;
80562306a36Sopenharmony_ci		if (reg == LPASS_HDMI_TX_CH_LSB_ADDR(v, i))
80662306a36Sopenharmony_ci			return true;
80762306a36Sopenharmony_ci		if (reg == LPASS_HDMI_TX_CH_MSB_ADDR(v, i))
80862306a36Sopenharmony_ci			return true;
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci	return false;
81162306a36Sopenharmony_ci}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_cistatic struct regmap_config lpass_hdmi_regmap_config = {
81462306a36Sopenharmony_ci	.name = "lpass_hdmi",
81562306a36Sopenharmony_ci	.reg_bits = 32,
81662306a36Sopenharmony_ci	.reg_stride = 4,
81762306a36Sopenharmony_ci	.val_bits = 32,
81862306a36Sopenharmony_ci	.writeable_reg = lpass_hdmi_regmap_writeable,
81962306a36Sopenharmony_ci	.readable_reg = lpass_hdmi_regmap_readable,
82062306a36Sopenharmony_ci	.volatile_reg = lpass_hdmi_regmap_volatile,
82162306a36Sopenharmony_ci	.cache_type = REGCACHE_FLAT,
82262306a36Sopenharmony_ci};
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_cistatic bool __lpass_rxtx_regmap_accessible(struct device *dev, unsigned int reg, bool rw)
82562306a36Sopenharmony_ci{
82662306a36Sopenharmony_ci	struct lpass_data *drvdata = dev_get_drvdata(dev);
82762306a36Sopenharmony_ci	struct lpass_variant *v = drvdata->variant;
82862306a36Sopenharmony_ci	int i;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	for (i = 0; i < v->rxtx_irq_ports; ++i) {
83162306a36Sopenharmony_ci		if (reg == LPAIF_RXTX_IRQCLEAR_REG(v, i))
83262306a36Sopenharmony_ci			return true;
83362306a36Sopenharmony_ci		if (reg == LPAIF_RXTX_IRQEN_REG(v, i))
83462306a36Sopenharmony_ci			return true;
83562306a36Sopenharmony_ci		if (reg == LPAIF_RXTX_IRQSTAT_REG(v, i))
83662306a36Sopenharmony_ci			return true;
83762306a36Sopenharmony_ci	}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	for (i = 0; i < v->rxtx_rdma_channels; ++i) {
84062306a36Sopenharmony_ci		if (reg == LPAIF_CDC_RXTX_RDMACTL_REG(v, i, LPASS_CDC_DMA_RX0))
84162306a36Sopenharmony_ci			return true;
84262306a36Sopenharmony_ci		if (reg == LPAIF_CDC_RXTX_RDMABASE_REG(v, i, LPASS_CDC_DMA_RX0))
84362306a36Sopenharmony_ci			return true;
84462306a36Sopenharmony_ci		if (reg == LPAIF_CDC_RXTX_RDMABUFF_REG(v, i, LPASS_CDC_DMA_RX0))
84562306a36Sopenharmony_ci			return true;
84662306a36Sopenharmony_ci		if (rw == LPASS_REG_READ) {
84762306a36Sopenharmony_ci			if (reg == LPAIF_CDC_RXTX_RDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
84862306a36Sopenharmony_ci				return true;
84962306a36Sopenharmony_ci		}
85062306a36Sopenharmony_ci		if (reg == LPAIF_CDC_RXTX_RDMAPER_REG(v, i, LPASS_CDC_DMA_RX0))
85162306a36Sopenharmony_ci			return true;
85262306a36Sopenharmony_ci		if (reg == LPAIF_CDC_RXTX_RDMA_INTF_REG(v, i, LPASS_CDC_DMA_RX0))
85362306a36Sopenharmony_ci			return true;
85462306a36Sopenharmony_ci	}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	for (i = 0; i < v->rxtx_wrdma_channels; ++i) {
85762306a36Sopenharmony_ci		if (reg == LPAIF_CDC_RXTX_WRDMACTL_REG(v, i + v->rxtx_wrdma_channel_start,
85862306a36Sopenharmony_ci							LPASS_CDC_DMA_TX3))
85962306a36Sopenharmony_ci			return true;
86062306a36Sopenharmony_ci		if (reg == LPAIF_CDC_RXTX_WRDMABASE_REG(v, i + v->rxtx_wrdma_channel_start,
86162306a36Sopenharmony_ci							LPASS_CDC_DMA_TX3))
86262306a36Sopenharmony_ci			return true;
86362306a36Sopenharmony_ci		if (reg == LPAIF_CDC_RXTX_WRDMABUFF_REG(v, i + v->rxtx_wrdma_channel_start,
86462306a36Sopenharmony_ci							LPASS_CDC_DMA_TX3))
86562306a36Sopenharmony_ci			return true;
86662306a36Sopenharmony_ci		if (rw == LPASS_REG_READ) {
86762306a36Sopenharmony_ci			if (reg == LPAIF_CDC_RXTX_WRDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
86862306a36Sopenharmony_ci				return true;
86962306a36Sopenharmony_ci		}
87062306a36Sopenharmony_ci		if (reg == LPAIF_CDC_RXTX_WRDMAPER_REG(v, i + v->rxtx_wrdma_channel_start,
87162306a36Sopenharmony_ci							LPASS_CDC_DMA_TX3))
87262306a36Sopenharmony_ci			return true;
87362306a36Sopenharmony_ci		if (reg == LPAIF_CDC_RXTX_WRDMA_INTF_REG(v, i + v->rxtx_wrdma_channel_start,
87462306a36Sopenharmony_ci							LPASS_CDC_DMA_TX3))
87562306a36Sopenharmony_ci			return true;
87662306a36Sopenharmony_ci	}
87762306a36Sopenharmony_ci	return false;
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_cistatic bool lpass_rxtx_regmap_writeable(struct device *dev, unsigned int reg)
88162306a36Sopenharmony_ci{
88262306a36Sopenharmony_ci	return __lpass_rxtx_regmap_accessible(dev, reg, LPASS_REG_WRITE);
88362306a36Sopenharmony_ci}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_cistatic bool lpass_rxtx_regmap_readable(struct device *dev, unsigned int reg)
88662306a36Sopenharmony_ci{
88762306a36Sopenharmony_ci	return __lpass_rxtx_regmap_accessible(dev, reg, LPASS_REG_READ);
88862306a36Sopenharmony_ci}
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_cistatic bool lpass_rxtx_regmap_volatile(struct device *dev, unsigned int reg)
89162306a36Sopenharmony_ci{
89262306a36Sopenharmony_ci	struct lpass_data *drvdata = dev_get_drvdata(dev);
89362306a36Sopenharmony_ci	struct lpass_variant *v = drvdata->variant;
89462306a36Sopenharmony_ci	int i;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	for (i = 0; i < v->rxtx_irq_ports; ++i) {
89762306a36Sopenharmony_ci		if (reg == LPAIF_RXTX_IRQCLEAR_REG(v, i))
89862306a36Sopenharmony_ci			return true;
89962306a36Sopenharmony_ci		if (reg == LPAIF_RXTX_IRQSTAT_REG(v, i))
90062306a36Sopenharmony_ci			return true;
90162306a36Sopenharmony_ci	}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	for (i = 0; i < v->rxtx_rdma_channels; ++i)
90462306a36Sopenharmony_ci		if (reg == LPAIF_CDC_RXTX_RDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
90562306a36Sopenharmony_ci			return true;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	for (i = 0; i < v->rxtx_wrdma_channels; ++i)
90862306a36Sopenharmony_ci		if (reg == LPAIF_CDC_RXTX_WRDMACURR_REG(v, i + v->rxtx_wrdma_channel_start,
90962306a36Sopenharmony_ci							LPASS_CDC_DMA_TX3))
91062306a36Sopenharmony_ci			return true;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	return false;
91362306a36Sopenharmony_ci}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_cistatic bool __lpass_va_regmap_accessible(struct device *dev, unsigned int reg, bool rw)
91662306a36Sopenharmony_ci{
91762306a36Sopenharmony_ci	struct lpass_data *drvdata = dev_get_drvdata(dev);
91862306a36Sopenharmony_ci	struct lpass_variant *v = drvdata->variant;
91962306a36Sopenharmony_ci	int i;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	for (i = 0; i < v->va_irq_ports; ++i) {
92262306a36Sopenharmony_ci		if (reg == LPAIF_VA_IRQCLEAR_REG(v, i))
92362306a36Sopenharmony_ci			return true;
92462306a36Sopenharmony_ci		if (reg == LPAIF_VA_IRQEN_REG(v, i))
92562306a36Sopenharmony_ci			return true;
92662306a36Sopenharmony_ci		if (reg == LPAIF_VA_IRQSTAT_REG(v, i))
92762306a36Sopenharmony_ci			return true;
92862306a36Sopenharmony_ci	}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	for (i = 0; i < v->va_wrdma_channels; ++i) {
93162306a36Sopenharmony_ci		if (reg == LPAIF_CDC_VA_WRDMACTL_REG(v, i + v->va_wrdma_channel_start,
93262306a36Sopenharmony_ci							LPASS_CDC_DMA_VA_TX0))
93362306a36Sopenharmony_ci			return true;
93462306a36Sopenharmony_ci		if (reg == LPAIF_CDC_VA_WRDMABASE_REG(v, i + v->va_wrdma_channel_start,
93562306a36Sopenharmony_ci							LPASS_CDC_DMA_VA_TX0))
93662306a36Sopenharmony_ci			return true;
93762306a36Sopenharmony_ci		if (reg == LPAIF_CDC_VA_WRDMABUFF_REG(v, i + v->va_wrdma_channel_start,
93862306a36Sopenharmony_ci							LPASS_CDC_DMA_VA_TX0))
93962306a36Sopenharmony_ci			return true;
94062306a36Sopenharmony_ci		if (rw == LPASS_REG_READ) {
94162306a36Sopenharmony_ci			if (reg == LPAIF_CDC_VA_WRDMACURR_REG(v, i + v->va_wrdma_channel_start,
94262306a36Sopenharmony_ci							LPASS_CDC_DMA_VA_TX0))
94362306a36Sopenharmony_ci				return true;
94462306a36Sopenharmony_ci		}
94562306a36Sopenharmony_ci		if (reg == LPAIF_CDC_VA_WRDMAPER_REG(v, i + v->va_wrdma_channel_start,
94662306a36Sopenharmony_ci							LPASS_CDC_DMA_VA_TX0))
94762306a36Sopenharmony_ci			return true;
94862306a36Sopenharmony_ci		if (reg == LPAIF_CDC_VA_WRDMA_INTF_REG(v, i + v->va_wrdma_channel_start,
94962306a36Sopenharmony_ci							LPASS_CDC_DMA_VA_TX0))
95062306a36Sopenharmony_ci			return true;
95162306a36Sopenharmony_ci	}
95262306a36Sopenharmony_ci	return false;
95362306a36Sopenharmony_ci}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_cistatic bool lpass_va_regmap_writeable(struct device *dev, unsigned int reg)
95662306a36Sopenharmony_ci{
95762306a36Sopenharmony_ci	return __lpass_va_regmap_accessible(dev, reg, LPASS_REG_WRITE);
95862306a36Sopenharmony_ci}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_cistatic bool lpass_va_regmap_readable(struct device *dev, unsigned int reg)
96162306a36Sopenharmony_ci{
96262306a36Sopenharmony_ci	return __lpass_va_regmap_accessible(dev, reg, LPASS_REG_READ);
96362306a36Sopenharmony_ci}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_cistatic bool lpass_va_regmap_volatile(struct device *dev, unsigned int reg)
96662306a36Sopenharmony_ci{
96762306a36Sopenharmony_ci	struct lpass_data *drvdata = dev_get_drvdata(dev);
96862306a36Sopenharmony_ci	struct lpass_variant *v = drvdata->variant;
96962306a36Sopenharmony_ci	int i;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	for (i = 0; i < v->va_irq_ports; ++i) {
97262306a36Sopenharmony_ci		if (reg == LPAIF_VA_IRQCLEAR_REG(v, i))
97362306a36Sopenharmony_ci			return true;
97462306a36Sopenharmony_ci		if (reg == LPAIF_VA_IRQSTAT_REG(v, i))
97562306a36Sopenharmony_ci			return true;
97662306a36Sopenharmony_ci	}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	for (i = 0; i < v->va_wrdma_channels; ++i) {
97962306a36Sopenharmony_ci		if (reg == LPAIF_CDC_VA_WRDMACURR_REG(v, i + v->va_wrdma_channel_start,
98062306a36Sopenharmony_ci							LPASS_CDC_DMA_VA_TX0))
98162306a36Sopenharmony_ci			return true;
98262306a36Sopenharmony_ci	}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	return false;
98562306a36Sopenharmony_ci}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_cistatic struct regmap_config lpass_rxtx_regmap_config = {
98862306a36Sopenharmony_ci	.reg_bits = 32,
98962306a36Sopenharmony_ci	.reg_stride = 4,
99062306a36Sopenharmony_ci	.val_bits = 32,
99162306a36Sopenharmony_ci	.writeable_reg = lpass_rxtx_regmap_writeable,
99262306a36Sopenharmony_ci	.readable_reg = lpass_rxtx_regmap_readable,
99362306a36Sopenharmony_ci	.volatile_reg = lpass_rxtx_regmap_volatile,
99462306a36Sopenharmony_ci	.cache_type = REGCACHE_FLAT,
99562306a36Sopenharmony_ci};
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_cistatic struct regmap_config lpass_va_regmap_config = {
99862306a36Sopenharmony_ci	.reg_bits = 32,
99962306a36Sopenharmony_ci	.reg_stride = 4,
100062306a36Sopenharmony_ci	.val_bits = 32,
100162306a36Sopenharmony_ci	.writeable_reg = lpass_va_regmap_writeable,
100262306a36Sopenharmony_ci	.readable_reg = lpass_va_regmap_readable,
100362306a36Sopenharmony_ci	.volatile_reg = lpass_va_regmap_volatile,
100462306a36Sopenharmony_ci	.cache_type = REGCACHE_FLAT,
100562306a36Sopenharmony_ci};
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_cistatic unsigned int of_lpass_cpu_parse_sd_lines(struct device *dev,
100862306a36Sopenharmony_ci						struct device_node *node,
100962306a36Sopenharmony_ci						const char *name)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	unsigned int lines[LPASS_CPU_MAX_MI2S_LINES];
101262306a36Sopenharmony_ci	unsigned int sd_line_mask = 0;
101362306a36Sopenharmony_ci	int num_lines, i;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	num_lines = of_property_read_variable_u32_array(node, name, lines, 0,
101662306a36Sopenharmony_ci							LPASS_CPU_MAX_MI2S_LINES);
101762306a36Sopenharmony_ci	if (num_lines < 0)
101862306a36Sopenharmony_ci		return LPAIF_I2SCTL_MODE_NONE;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	for (i = 0; i < num_lines; i++)
102162306a36Sopenharmony_ci		sd_line_mask |= BIT(lines[i]);
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	switch (sd_line_mask) {
102462306a36Sopenharmony_ci	case LPASS_CPU_I2S_SD0_MASK:
102562306a36Sopenharmony_ci		return LPAIF_I2SCTL_MODE_SD0;
102662306a36Sopenharmony_ci	case LPASS_CPU_I2S_SD1_MASK:
102762306a36Sopenharmony_ci		return LPAIF_I2SCTL_MODE_SD1;
102862306a36Sopenharmony_ci	case LPASS_CPU_I2S_SD2_MASK:
102962306a36Sopenharmony_ci		return LPAIF_I2SCTL_MODE_SD2;
103062306a36Sopenharmony_ci	case LPASS_CPU_I2S_SD3_MASK:
103162306a36Sopenharmony_ci		return LPAIF_I2SCTL_MODE_SD3;
103262306a36Sopenharmony_ci	case LPASS_CPU_I2S_SD0_1_MASK:
103362306a36Sopenharmony_ci		return LPAIF_I2SCTL_MODE_QUAD01;
103462306a36Sopenharmony_ci	case LPASS_CPU_I2S_SD2_3_MASK:
103562306a36Sopenharmony_ci		return LPAIF_I2SCTL_MODE_QUAD23;
103662306a36Sopenharmony_ci	case LPASS_CPU_I2S_SD0_1_2_MASK:
103762306a36Sopenharmony_ci		return LPAIF_I2SCTL_MODE_6CH;
103862306a36Sopenharmony_ci	case LPASS_CPU_I2S_SD0_1_2_3_MASK:
103962306a36Sopenharmony_ci		return LPAIF_I2SCTL_MODE_8CH;
104062306a36Sopenharmony_ci	default:
104162306a36Sopenharmony_ci		dev_err(dev, "Unsupported SD line mask: %#x\n", sd_line_mask);
104262306a36Sopenharmony_ci		return LPAIF_I2SCTL_MODE_NONE;
104362306a36Sopenharmony_ci	}
104462306a36Sopenharmony_ci}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_cistatic void of_lpass_cpu_parse_dai_data(struct device *dev,
104762306a36Sopenharmony_ci					struct lpass_data *data)
104862306a36Sopenharmony_ci{
104962306a36Sopenharmony_ci	struct device_node *node;
105062306a36Sopenharmony_ci	int ret, i, id;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	/* Allow all channels by default for backwards compatibility */
105362306a36Sopenharmony_ci	for (i = 0; i < data->variant->num_dai; i++) {
105462306a36Sopenharmony_ci		id = data->variant->dai_driver[i].id;
105562306a36Sopenharmony_ci		data->mi2s_playback_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH;
105662306a36Sopenharmony_ci		data->mi2s_capture_sd_mode[id] = LPAIF_I2SCTL_MODE_8CH;
105762306a36Sopenharmony_ci	}
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	for_each_child_of_node(dev->of_node, node) {
106062306a36Sopenharmony_ci		ret = of_property_read_u32(node, "reg", &id);
106162306a36Sopenharmony_ci		if (ret || id < 0) {
106262306a36Sopenharmony_ci			dev_err(dev, "valid dai id not found: %d\n", ret);
106362306a36Sopenharmony_ci			continue;
106462306a36Sopenharmony_ci		}
106562306a36Sopenharmony_ci		if (id == LPASS_DP_RX) {
106662306a36Sopenharmony_ci			data->hdmi_port_enable = 1;
106762306a36Sopenharmony_ci		} else if (is_cdc_dma_port(id)) {
106862306a36Sopenharmony_ci			data->codec_dma_enable = 1;
106962306a36Sopenharmony_ci		} else {
107062306a36Sopenharmony_ci			data->mi2s_playback_sd_mode[id] =
107162306a36Sopenharmony_ci				of_lpass_cpu_parse_sd_lines(dev, node,
107262306a36Sopenharmony_ci							    "qcom,playback-sd-lines");
107362306a36Sopenharmony_ci			data->mi2s_capture_sd_mode[id] =
107462306a36Sopenharmony_ci				of_lpass_cpu_parse_sd_lines(dev, node,
107562306a36Sopenharmony_ci						    "qcom,capture-sd-lines");
107662306a36Sopenharmony_ci		}
107762306a36Sopenharmony_ci	}
107862306a36Sopenharmony_ci}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_cistatic int of_lpass_cdc_dma_clks_parse(struct device *dev,
108162306a36Sopenharmony_ci					struct lpass_data *data)
108262306a36Sopenharmony_ci{
108362306a36Sopenharmony_ci	data->codec_mem0 = devm_clk_get(dev, "audio_cc_codec_mem0");
108462306a36Sopenharmony_ci	if (IS_ERR(data->codec_mem0))
108562306a36Sopenharmony_ci		return PTR_ERR(data->codec_mem0);
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	data->codec_mem1 = devm_clk_get(dev, "audio_cc_codec_mem1");
108862306a36Sopenharmony_ci	if (IS_ERR(data->codec_mem1))
108962306a36Sopenharmony_ci		return PTR_ERR(data->codec_mem1);
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	data->codec_mem2 = devm_clk_get(dev, "audio_cc_codec_mem2");
109262306a36Sopenharmony_ci	if (IS_ERR(data->codec_mem2))
109362306a36Sopenharmony_ci		return PTR_ERR(data->codec_mem2);
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	data->va_mem0 = devm_clk_get(dev, "aon_cc_va_mem0");
109662306a36Sopenharmony_ci	if (IS_ERR(data->va_mem0))
109762306a36Sopenharmony_ci		return PTR_ERR(data->va_mem0);
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	return 0;
110062306a36Sopenharmony_ci}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ciint asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
110362306a36Sopenharmony_ci{
110462306a36Sopenharmony_ci	struct lpass_data *drvdata;
110562306a36Sopenharmony_ci	struct device_node *dsp_of_node;
110662306a36Sopenharmony_ci	struct resource *res;
110762306a36Sopenharmony_ci	struct lpass_variant *variant;
110862306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
110962306a36Sopenharmony_ci	const struct of_device_id *match;
111062306a36Sopenharmony_ci	int ret, i, dai_id;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
111362306a36Sopenharmony_ci	if (dsp_of_node) {
111462306a36Sopenharmony_ci		dev_err(dev, "DSP exists and holds audio resources\n");
111562306a36Sopenharmony_ci		of_node_put(dsp_of_node);
111662306a36Sopenharmony_ci		return -EBUSY;
111762306a36Sopenharmony_ci	}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	drvdata = devm_kzalloc(dev, sizeof(struct lpass_data), GFP_KERNEL);
112062306a36Sopenharmony_ci	if (!drvdata)
112162306a36Sopenharmony_ci		return -ENOMEM;
112262306a36Sopenharmony_ci	platform_set_drvdata(pdev, drvdata);
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	match = of_match_device(dev->driver->of_match_table, dev);
112562306a36Sopenharmony_ci	if (!match || !match->data)
112662306a36Sopenharmony_ci		return -EINVAL;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	if (of_device_is_compatible(dev->of_node, "qcom,lpass-cpu-apq8016")) {
112962306a36Sopenharmony_ci		dev_warn(dev, "%s compatible is deprecated\n",
113062306a36Sopenharmony_ci			 match->compatible);
113162306a36Sopenharmony_ci	}
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	drvdata->variant = (struct lpass_variant *)match->data;
113462306a36Sopenharmony_ci	variant = drvdata->variant;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	of_lpass_cpu_parse_dai_data(dev, drvdata);
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	if (drvdata->codec_dma_enable) {
113962306a36Sopenharmony_ci		drvdata->rxtx_lpaif =
114062306a36Sopenharmony_ci				devm_platform_ioremap_resource_byname(pdev, "lpass-rxtx-lpaif");
114162306a36Sopenharmony_ci		if (IS_ERR(drvdata->rxtx_lpaif))
114262306a36Sopenharmony_ci			return PTR_ERR(drvdata->rxtx_lpaif);
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci		drvdata->va_lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-va-lpaif");
114562306a36Sopenharmony_ci		if (IS_ERR(drvdata->va_lpaif))
114662306a36Sopenharmony_ci			return PTR_ERR(drvdata->va_lpaif);
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci		lpass_rxtx_regmap_config.max_register = LPAIF_CDC_RXTX_WRDMAPER_REG(variant,
114962306a36Sopenharmony_ci					variant->rxtx_wrdma_channels +
115062306a36Sopenharmony_ci					variant->rxtx_wrdma_channel_start, LPASS_CDC_DMA_TX3);
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci		drvdata->rxtx_lpaif_map = devm_regmap_init_mmio(dev, drvdata->rxtx_lpaif,
115362306a36Sopenharmony_ci					&lpass_rxtx_regmap_config);
115462306a36Sopenharmony_ci		if (IS_ERR(drvdata->rxtx_lpaif_map))
115562306a36Sopenharmony_ci			return PTR_ERR(drvdata->rxtx_lpaif_map);
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci		lpass_va_regmap_config.max_register = LPAIF_CDC_VA_WRDMAPER_REG(variant,
115862306a36Sopenharmony_ci					variant->va_wrdma_channels +
115962306a36Sopenharmony_ci					variant->va_wrdma_channel_start, LPASS_CDC_DMA_VA_TX0);
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci		drvdata->va_lpaif_map = devm_regmap_init_mmio(dev, drvdata->va_lpaif,
116262306a36Sopenharmony_ci					&lpass_va_regmap_config);
116362306a36Sopenharmony_ci		if (IS_ERR(drvdata->va_lpaif_map))
116462306a36Sopenharmony_ci			return PTR_ERR(drvdata->va_lpaif_map);
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci		ret = of_lpass_cdc_dma_clks_parse(dev, drvdata);
116762306a36Sopenharmony_ci		if (ret) {
116862306a36Sopenharmony_ci			dev_err(dev, "failed to get cdc dma clocks %d\n", ret);
116962306a36Sopenharmony_ci			return ret;
117062306a36Sopenharmony_ci		}
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-rxtx-cdc-dma-lpm");
117362306a36Sopenharmony_ci		drvdata->rxtx_cdc_dma_lpm_buf = res->start;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-va-cdc-dma-lpm");
117662306a36Sopenharmony_ci		drvdata->va_cdc_dma_lpm_buf = res->start;
117762306a36Sopenharmony_ci	}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	drvdata->lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-lpaif");
118062306a36Sopenharmony_ci	if (IS_ERR(drvdata->lpaif))
118162306a36Sopenharmony_ci		return PTR_ERR(drvdata->lpaif);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	lpass_cpu_regmap_config.max_register = LPAIF_WRDMAPER_REG(variant,
118462306a36Sopenharmony_ci						variant->wrdma_channels +
118562306a36Sopenharmony_ci						variant->wrdma_channel_start);
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	drvdata->lpaif_map = devm_regmap_init_mmio(dev, drvdata->lpaif,
118862306a36Sopenharmony_ci			&lpass_cpu_regmap_config);
118962306a36Sopenharmony_ci	if (IS_ERR(drvdata->lpaif_map)) {
119062306a36Sopenharmony_ci		dev_err(dev, "error initializing regmap: %ld\n",
119162306a36Sopenharmony_ci			PTR_ERR(drvdata->lpaif_map));
119262306a36Sopenharmony_ci		return PTR_ERR(drvdata->lpaif_map);
119362306a36Sopenharmony_ci	}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	if (drvdata->hdmi_port_enable) {
119662306a36Sopenharmony_ci		drvdata->hdmiif = devm_platform_ioremap_resource_byname(pdev, "lpass-hdmiif");
119762306a36Sopenharmony_ci		if (IS_ERR(drvdata->hdmiif))
119862306a36Sopenharmony_ci			return PTR_ERR(drvdata->hdmiif);
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci		lpass_hdmi_regmap_config.max_register = LPAIF_HDMI_RDMAPER_REG(variant,
120162306a36Sopenharmony_ci					variant->hdmi_rdma_channels - 1);
120262306a36Sopenharmony_ci		drvdata->hdmiif_map = devm_regmap_init_mmio(dev, drvdata->hdmiif,
120362306a36Sopenharmony_ci					&lpass_hdmi_regmap_config);
120462306a36Sopenharmony_ci		if (IS_ERR(drvdata->hdmiif_map)) {
120562306a36Sopenharmony_ci			dev_err(dev, "error initializing regmap: %ld\n",
120662306a36Sopenharmony_ci			PTR_ERR(drvdata->hdmiif_map));
120762306a36Sopenharmony_ci			return PTR_ERR(drvdata->hdmiif_map);
120862306a36Sopenharmony_ci		}
120962306a36Sopenharmony_ci	}
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	if (variant->init) {
121262306a36Sopenharmony_ci		ret = variant->init(pdev);
121362306a36Sopenharmony_ci		if (ret) {
121462306a36Sopenharmony_ci			dev_err(dev, "error initializing variant: %d\n", ret);
121562306a36Sopenharmony_ci			return ret;
121662306a36Sopenharmony_ci		}
121762306a36Sopenharmony_ci	}
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	for (i = 0; i < variant->num_dai; i++) {
122062306a36Sopenharmony_ci		dai_id = variant->dai_driver[i].id;
122162306a36Sopenharmony_ci		if (dai_id == LPASS_DP_RX || is_cdc_dma_port(dai_id))
122262306a36Sopenharmony_ci			continue;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci		drvdata->mi2s_osr_clk[dai_id] = devm_clk_get_optional(dev,
122562306a36Sopenharmony_ci					     variant->dai_osr_clk_names[i]);
122662306a36Sopenharmony_ci		drvdata->mi2s_bit_clk[dai_id] = devm_clk_get(dev,
122762306a36Sopenharmony_ci						variant->dai_bit_clk_names[i]);
122862306a36Sopenharmony_ci		if (IS_ERR(drvdata->mi2s_bit_clk[dai_id])) {
122962306a36Sopenharmony_ci			dev_err(dev,
123062306a36Sopenharmony_ci				"error getting %s: %ld\n",
123162306a36Sopenharmony_ci				variant->dai_bit_clk_names[i],
123262306a36Sopenharmony_ci				PTR_ERR(drvdata->mi2s_bit_clk[dai_id]));
123362306a36Sopenharmony_ci			return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
123462306a36Sopenharmony_ci		}
123562306a36Sopenharmony_ci		if (drvdata->mi2s_playback_sd_mode[dai_id] ==
123662306a36Sopenharmony_ci			LPAIF_I2SCTL_MODE_QUAD01) {
123762306a36Sopenharmony_ci			variant->dai_driver[dai_id].playback.channels_min = 4;
123862306a36Sopenharmony_ci			variant->dai_driver[dai_id].playback.channels_max = 4;
123962306a36Sopenharmony_ci		}
124062306a36Sopenharmony_ci	}
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	/* Allocation for i2sctl regmap fields */
124362306a36Sopenharmony_ci	drvdata->i2sctl = devm_kzalloc(&pdev->dev, sizeof(struct lpaif_i2sctl),
124462306a36Sopenharmony_ci					GFP_KERNEL);
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	/* Initialize bitfields for dai I2SCTL register */
124762306a36Sopenharmony_ci	ret = lpass_cpu_init_i2sctl_bitfields(dev, drvdata->i2sctl,
124862306a36Sopenharmony_ci						drvdata->lpaif_map);
124962306a36Sopenharmony_ci	if (ret) {
125062306a36Sopenharmony_ci		dev_err(dev, "error init i2sctl field: %d\n", ret);
125162306a36Sopenharmony_ci		return ret;
125262306a36Sopenharmony_ci	}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	if (drvdata->hdmi_port_enable) {
125562306a36Sopenharmony_ci		ret = lpass_hdmi_init_bitfields(dev, drvdata->hdmiif_map);
125662306a36Sopenharmony_ci		if (ret) {
125762306a36Sopenharmony_ci			dev_err(dev, "%s error  hdmi init failed\n", __func__);
125862306a36Sopenharmony_ci			return ret;
125962306a36Sopenharmony_ci		}
126062306a36Sopenharmony_ci	}
126162306a36Sopenharmony_ci	ret = devm_snd_soc_register_component(dev,
126262306a36Sopenharmony_ci					      &lpass_cpu_comp_driver,
126362306a36Sopenharmony_ci					      variant->dai_driver,
126462306a36Sopenharmony_ci					      variant->num_dai);
126562306a36Sopenharmony_ci	if (ret) {
126662306a36Sopenharmony_ci		dev_err(dev, "error registering cpu driver: %d\n", ret);
126762306a36Sopenharmony_ci		goto err;
126862306a36Sopenharmony_ci	}
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	ret = asoc_qcom_lpass_platform_register(pdev);
127162306a36Sopenharmony_ci	if (ret) {
127262306a36Sopenharmony_ci		dev_err(dev, "error registering platform driver: %d\n", ret);
127362306a36Sopenharmony_ci		goto err;
127462306a36Sopenharmony_ci	}
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_cierr:
127762306a36Sopenharmony_ci	return ret;
127862306a36Sopenharmony_ci}
127962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe);
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ciint asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev)
128262306a36Sopenharmony_ci{
128362306a36Sopenharmony_ci	struct lpass_data *drvdata = platform_get_drvdata(pdev);
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	if (drvdata->variant->exit)
128662306a36Sopenharmony_ci		drvdata->variant->exit(pdev);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	return 0;
129062306a36Sopenharmony_ci}
129162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove);
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_civoid asoc_qcom_lpass_cpu_platform_shutdown(struct platform_device *pdev)
129462306a36Sopenharmony_ci{
129562306a36Sopenharmony_ci	struct lpass_data *drvdata = platform_get_drvdata(pdev);
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	if (drvdata->variant->exit)
129862306a36Sopenharmony_ci		drvdata->variant->exit(pdev);
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci}
130162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_shutdown);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ciMODULE_DESCRIPTION("QTi LPASS CPU Driver");
130462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1305