162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// Socionext UniPhier AIO ALSA common driver.
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci// Copyright (c) 2016-2018 Socionext Inc.
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/bitfield.h>
862306a36Sopenharmony_ci#include <linux/errno.h>
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <sound/core.h>
1262306a36Sopenharmony_ci#include <sound/pcm.h>
1362306a36Sopenharmony_ci#include <sound/pcm_params.h>
1462306a36Sopenharmony_ci#include <sound/soc.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "aio.h"
1762306a36Sopenharmony_ci#include "aio-reg.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic u64 rb_cnt(u64 wr, u64 rd, u64 len)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	if (rd <= wr)
2262306a36Sopenharmony_ci		return wr - rd;
2362306a36Sopenharmony_ci	else
2462306a36Sopenharmony_ci		return len - (rd - wr);
2562306a36Sopenharmony_ci}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic u64 rb_cnt_to_end(u64 wr, u64 rd, u64 len)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	if (rd <= wr)
3062306a36Sopenharmony_ci		return wr - rd;
3162306a36Sopenharmony_ci	else
3262306a36Sopenharmony_ci		return len - rd;
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic u64 rb_space(u64 wr, u64 rd, u64 len)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	if (rd <= wr)
3862306a36Sopenharmony_ci		return len - (wr - rd) - 8;
3962306a36Sopenharmony_ci	else
4062306a36Sopenharmony_ci		return rd - wr - 8;
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic u64 rb_space_to_end(u64 wr, u64 rd, u64 len)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	if (rd > wr)
4662306a36Sopenharmony_ci		return rd - wr - 8;
4762306a36Sopenharmony_ci	else if (rd > 0)
4862306a36Sopenharmony_ci		return len - wr;
4962306a36Sopenharmony_ci	else
5062306a36Sopenharmony_ci		return len - wr - 8;
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ciu64 aio_rb_cnt(struct uniphier_aio_sub *sub)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	return rb_cnt(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ciu64 aio_rbt_cnt_to_end(struct uniphier_aio_sub *sub)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	return rb_cnt_to_end(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ciu64 aio_rb_space(struct uniphier_aio_sub *sub)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	return rb_space(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ciu64 aio_rb_space_to_end(struct uniphier_aio_sub *sub)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	return rb_space_to_end(sub->wr_offs, sub->rd_offs, sub->compr_bytes);
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/**
7462306a36Sopenharmony_ci * aio_iecout_set_enable - setup IEC output via SoC glue
7562306a36Sopenharmony_ci * @chip: the AIO chip pointer
7662306a36Sopenharmony_ci * @enable: false to stop the output, true to start
7762306a36Sopenharmony_ci *
7862306a36Sopenharmony_ci * Set enabled or disabled S/PDIF signal output to out of SoC via AOnIEC pins.
7962306a36Sopenharmony_ci * This function need to call at driver startup.
8062306a36Sopenharmony_ci *
8162306a36Sopenharmony_ci * The regmap of SoC glue is specified by 'socionext,syscon' optional property
8262306a36Sopenharmony_ci * of DT. This function has no effect if no property.
8362306a36Sopenharmony_ci */
8462306a36Sopenharmony_civoid aio_iecout_set_enable(struct uniphier_aio_chip *chip, bool enable)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	struct regmap *r = chip->regmap_sg;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	if (!r)
8962306a36Sopenharmony_ci		return;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	regmap_write(r, SG_AOUTEN, (enable) ? ~0 : 0);
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/**
9562306a36Sopenharmony_ci * aio_chip_set_pll - set frequency to audio PLL
9662306a36Sopenharmony_ci * @chip: the AIO chip pointer
9762306a36Sopenharmony_ci * @pll_id: PLL
9862306a36Sopenharmony_ci * @freq: frequency in Hz, 0 is ignored
9962306a36Sopenharmony_ci *
10062306a36Sopenharmony_ci * Sets frequency of audio PLL. This function can be called anytime,
10162306a36Sopenharmony_ci * but it takes time till PLL is locked.
10262306a36Sopenharmony_ci *
10362306a36Sopenharmony_ci * Return: Zero if successful, otherwise a negative value on error.
10462306a36Sopenharmony_ci */
10562306a36Sopenharmony_ciint aio_chip_set_pll(struct uniphier_aio_chip *chip, int pll_id,
10662306a36Sopenharmony_ci		     unsigned int freq)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	struct device *dev = &chip->pdev->dev;
10962306a36Sopenharmony_ci	struct regmap *r = chip->regmap;
11062306a36Sopenharmony_ci	int shift;
11162306a36Sopenharmony_ci	u32 v;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	/* Not change */
11462306a36Sopenharmony_ci	if (freq == 0)
11562306a36Sopenharmony_ci		return 0;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	switch (pll_id) {
11862306a36Sopenharmony_ci	case AUD_PLL_A1:
11962306a36Sopenharmony_ci		shift = 0;
12062306a36Sopenharmony_ci		break;
12162306a36Sopenharmony_ci	case AUD_PLL_F1:
12262306a36Sopenharmony_ci		shift = 1;
12362306a36Sopenharmony_ci		break;
12462306a36Sopenharmony_ci	case AUD_PLL_A2:
12562306a36Sopenharmony_ci		shift = 2;
12662306a36Sopenharmony_ci		break;
12762306a36Sopenharmony_ci	case AUD_PLL_F2:
12862306a36Sopenharmony_ci		shift = 3;
12962306a36Sopenharmony_ci		break;
13062306a36Sopenharmony_ci	default:
13162306a36Sopenharmony_ci		dev_err(dev, "PLL(%d) not supported\n", pll_id);
13262306a36Sopenharmony_ci		return -EINVAL;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	switch (freq) {
13662306a36Sopenharmony_ci	case 36864000:
13762306a36Sopenharmony_ci		v = A2APLLCTR1_APLLX_36MHZ;
13862306a36Sopenharmony_ci		break;
13962306a36Sopenharmony_ci	case 33868800:
14062306a36Sopenharmony_ci		v = A2APLLCTR1_APLLX_33MHZ;
14162306a36Sopenharmony_ci		break;
14262306a36Sopenharmony_ci	default:
14362306a36Sopenharmony_ci		dev_err(dev, "PLL frequency not supported(%d)\n", freq);
14462306a36Sopenharmony_ci		return -EINVAL;
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci	chip->plls[pll_id].freq = freq;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	regmap_update_bits(r, A2APLLCTR1, A2APLLCTR1_APLLX_MASK << shift,
14962306a36Sopenharmony_ci			   v << shift);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	return 0;
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci/**
15562306a36Sopenharmony_ci * aio_chip_init - initialize AIO whole settings
15662306a36Sopenharmony_ci * @chip: the AIO chip pointer
15762306a36Sopenharmony_ci *
15862306a36Sopenharmony_ci * Sets AIO fixed and whole device settings to AIO.
15962306a36Sopenharmony_ci * This function need to call once at driver startup.
16062306a36Sopenharmony_ci *
16162306a36Sopenharmony_ci * The register area that is changed by this function is shared by all
16262306a36Sopenharmony_ci * modules of AIO. But there is not race condition since this function
16362306a36Sopenharmony_ci * has always set the same initialize values.
16462306a36Sopenharmony_ci */
16562306a36Sopenharmony_civoid aio_chip_init(struct uniphier_aio_chip *chip)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct regmap *r = chip->regmap;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	regmap_update_bits(r, A2APLLCTR0,
17062306a36Sopenharmony_ci			   A2APLLCTR0_APLLXPOW_MASK,
17162306a36Sopenharmony_ci			   A2APLLCTR0_APLLXPOW_PWON);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	regmap_update_bits(r, A2EXMCLKSEL0,
17462306a36Sopenharmony_ci			   A2EXMCLKSEL0_EXMCLK_MASK,
17562306a36Sopenharmony_ci			   A2EXMCLKSEL0_EXMCLK_OUTPUT);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	regmap_update_bits(r, A2AIOINPUTSEL, A2AIOINPUTSEL_RXSEL_MASK,
17862306a36Sopenharmony_ci			   A2AIOINPUTSEL_RXSEL_PCMI1_HDMIRX1 |
17962306a36Sopenharmony_ci			   A2AIOINPUTSEL_RXSEL_PCMI2_SIF |
18062306a36Sopenharmony_ci			   A2AIOINPUTSEL_RXSEL_PCMI3_EVEA |
18162306a36Sopenharmony_ci			   A2AIOINPUTSEL_RXSEL_IECI1_HDMIRX1);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if (chip->chip_spec->addr_ext)
18462306a36Sopenharmony_ci		regmap_update_bits(r, CDA2D_TEST, CDA2D_TEST_DDR_MODE_MASK,
18562306a36Sopenharmony_ci				   CDA2D_TEST_DDR_MODE_EXTON0);
18662306a36Sopenharmony_ci	else
18762306a36Sopenharmony_ci		regmap_update_bits(r, CDA2D_TEST, CDA2D_TEST_DDR_MODE_MASK,
18862306a36Sopenharmony_ci				   CDA2D_TEST_DDR_MODE_EXTOFF1);
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci/**
19262306a36Sopenharmony_ci * aio_init - initialize AIO substream
19362306a36Sopenharmony_ci * @sub: the AIO substream pointer
19462306a36Sopenharmony_ci *
19562306a36Sopenharmony_ci * Sets fixed settings of each AIO substreams.
19662306a36Sopenharmony_ci * This function need to call once at substream startup.
19762306a36Sopenharmony_ci *
19862306a36Sopenharmony_ci * Return: Zero if successful, otherwise a negative value on error.
19962306a36Sopenharmony_ci */
20062306a36Sopenharmony_ciint aio_init(struct uniphier_aio_sub *sub)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	struct device *dev = &sub->aio->chip->pdev->dev;
20362306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	regmap_write(r, A2RBNMAPCTR0(sub->swm->rb.hw),
20662306a36Sopenharmony_ci		     MAPCTR0_EN | sub->swm->rb.map);
20762306a36Sopenharmony_ci	regmap_write(r, A2CHNMAPCTR0(sub->swm->ch.hw),
20862306a36Sopenharmony_ci		     MAPCTR0_EN | sub->swm->ch.map);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	switch (sub->swm->type) {
21162306a36Sopenharmony_ci	case PORT_TYPE_I2S:
21262306a36Sopenharmony_ci	case PORT_TYPE_SPDIF:
21362306a36Sopenharmony_ci	case PORT_TYPE_EVE:
21462306a36Sopenharmony_ci		if (sub->swm->dir == PORT_DIR_INPUT) {
21562306a36Sopenharmony_ci			regmap_write(r, A2IIFNMAPCTR0(sub->swm->iif.hw),
21662306a36Sopenharmony_ci				     MAPCTR0_EN | sub->swm->iif.map);
21762306a36Sopenharmony_ci			regmap_write(r, A2IPORTNMAPCTR0(sub->swm->iport.hw),
21862306a36Sopenharmony_ci				     MAPCTR0_EN | sub->swm->iport.map);
21962306a36Sopenharmony_ci		} else {
22062306a36Sopenharmony_ci			regmap_write(r, A2OIFNMAPCTR0(sub->swm->oif.hw),
22162306a36Sopenharmony_ci				     MAPCTR0_EN | sub->swm->oif.map);
22262306a36Sopenharmony_ci			regmap_write(r, A2OPORTNMAPCTR0(sub->swm->oport.hw),
22362306a36Sopenharmony_ci				     MAPCTR0_EN | sub->swm->oport.map);
22462306a36Sopenharmony_ci		}
22562306a36Sopenharmony_ci		break;
22662306a36Sopenharmony_ci	case PORT_TYPE_CONV:
22762306a36Sopenharmony_ci		regmap_write(r, A2OIFNMAPCTR0(sub->swm->oif.hw),
22862306a36Sopenharmony_ci			     MAPCTR0_EN | sub->swm->oif.map);
22962306a36Sopenharmony_ci		regmap_write(r, A2OPORTNMAPCTR0(sub->swm->oport.hw),
23062306a36Sopenharmony_ci			     MAPCTR0_EN | sub->swm->oport.map);
23162306a36Sopenharmony_ci		regmap_write(r, A2CHNMAPCTR0(sub->swm->och.hw),
23262306a36Sopenharmony_ci			     MAPCTR0_EN | sub->swm->och.map);
23362306a36Sopenharmony_ci		regmap_write(r, A2IIFNMAPCTR0(sub->swm->iif.hw),
23462306a36Sopenharmony_ci			     MAPCTR0_EN | sub->swm->iif.map);
23562306a36Sopenharmony_ci		break;
23662306a36Sopenharmony_ci	default:
23762306a36Sopenharmony_ci		dev_err(dev, "Unknown port type %d.\n", sub->swm->type);
23862306a36Sopenharmony_ci		return -EINVAL;
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	return 0;
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci/**
24562306a36Sopenharmony_ci * aio_port_reset - reset AIO port block
24662306a36Sopenharmony_ci * @sub: the AIO substream pointer
24762306a36Sopenharmony_ci *
24862306a36Sopenharmony_ci * Resets the digital signal input/output port block of AIO.
24962306a36Sopenharmony_ci */
25062306a36Sopenharmony_civoid aio_port_reset(struct uniphier_aio_sub *sub)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if (sub->swm->dir == PORT_DIR_OUTPUT) {
25562306a36Sopenharmony_ci		regmap_write(r, AOUTRSTCTR0, BIT(sub->swm->oport.map));
25662306a36Sopenharmony_ci		regmap_write(r, AOUTRSTCTR1, BIT(sub->swm->oport.map));
25762306a36Sopenharmony_ci	} else {
25862306a36Sopenharmony_ci		regmap_update_bits(r, IPORTMXRSTCTR(sub->swm->iport.map),
25962306a36Sopenharmony_ci				   IPORTMXRSTCTR_RSTPI_MASK,
26062306a36Sopenharmony_ci				   IPORTMXRSTCTR_RSTPI_RESET);
26162306a36Sopenharmony_ci		regmap_update_bits(r, IPORTMXRSTCTR(sub->swm->iport.map),
26262306a36Sopenharmony_ci				   IPORTMXRSTCTR_RSTPI_MASK,
26362306a36Sopenharmony_ci				   IPORTMXRSTCTR_RSTPI_RELEASE);
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/**
26862306a36Sopenharmony_ci * aio_port_set_ch - set channels of LPCM
26962306a36Sopenharmony_ci * @sub: the AIO substream pointer, PCM substream only
27062306a36Sopenharmony_ci *
27162306a36Sopenharmony_ci * Set suitable slot selecting to input/output port block of AIO.
27262306a36Sopenharmony_ci *
27362306a36Sopenharmony_ci * This function may return error if non-PCM substream.
27462306a36Sopenharmony_ci *
27562306a36Sopenharmony_ci * Return: Zero if successful, otherwise a negative value on error.
27662306a36Sopenharmony_ci */
27762306a36Sopenharmony_cistatic int aio_port_set_ch(struct uniphier_aio_sub *sub)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
28062306a36Sopenharmony_ci	static const u32 slotsel_2ch[] = {
28162306a36Sopenharmony_ci		0, 0, 0, 0, 0,
28262306a36Sopenharmony_ci	};
28362306a36Sopenharmony_ci	static const u32 slotsel_multi[] = {
28462306a36Sopenharmony_ci		OPORTMXTYSLOTCTR_SLOTSEL_SLOT0,
28562306a36Sopenharmony_ci		OPORTMXTYSLOTCTR_SLOTSEL_SLOT1,
28662306a36Sopenharmony_ci		OPORTMXTYSLOTCTR_SLOTSEL_SLOT2,
28762306a36Sopenharmony_ci		OPORTMXTYSLOTCTR_SLOTSEL_SLOT3,
28862306a36Sopenharmony_ci		OPORTMXTYSLOTCTR_SLOTSEL_SLOT4,
28962306a36Sopenharmony_ci	};
29062306a36Sopenharmony_ci	u32 mode;
29162306a36Sopenharmony_ci	const u32 *slotsel;
29262306a36Sopenharmony_ci	int i;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	switch (params_channels(&sub->params)) {
29562306a36Sopenharmony_ci	case 8:
29662306a36Sopenharmony_ci	case 6:
29762306a36Sopenharmony_ci		mode = OPORTMXTYSLOTCTR_MODE;
29862306a36Sopenharmony_ci		slotsel = slotsel_multi;
29962306a36Sopenharmony_ci		break;
30062306a36Sopenharmony_ci	case 2:
30162306a36Sopenharmony_ci		mode = 0;
30262306a36Sopenharmony_ci		slotsel = slotsel_2ch;
30362306a36Sopenharmony_ci		break;
30462306a36Sopenharmony_ci	default:
30562306a36Sopenharmony_ci		return -EINVAL;
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	for (i = 0; i < AUD_MAX_SLOTSEL; i++) {
30962306a36Sopenharmony_ci		regmap_update_bits(r, OPORTMXTYSLOTCTR(sub->swm->oport.map, i),
31062306a36Sopenharmony_ci				   OPORTMXTYSLOTCTR_MODE, mode);
31162306a36Sopenharmony_ci		regmap_update_bits(r, OPORTMXTYSLOTCTR(sub->swm->oport.map, i),
31262306a36Sopenharmony_ci				   OPORTMXTYSLOTCTR_SLOTSEL_MASK, slotsel[i]);
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	return 0;
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci/**
31962306a36Sopenharmony_ci * aio_port_set_rate - set sampling rate of LPCM
32062306a36Sopenharmony_ci * @sub: the AIO substream pointer, PCM substream only
32162306a36Sopenharmony_ci * @rate: Sampling rate in Hz.
32262306a36Sopenharmony_ci *
32362306a36Sopenharmony_ci * Set suitable I2S format settings to input/output port block of AIO.
32462306a36Sopenharmony_ci * Parameter is specified by hw_params().
32562306a36Sopenharmony_ci *
32662306a36Sopenharmony_ci * This function may return error if non-PCM substream.
32762306a36Sopenharmony_ci *
32862306a36Sopenharmony_ci * Return: Zero if successful, otherwise a negative value on error.
32962306a36Sopenharmony_ci */
33062306a36Sopenharmony_cistatic int aio_port_set_rate(struct uniphier_aio_sub *sub, int rate)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
33362306a36Sopenharmony_ci	struct device *dev = &sub->aio->chip->pdev->dev;
33462306a36Sopenharmony_ci	u32 v;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (sub->swm->dir == PORT_DIR_OUTPUT) {
33762306a36Sopenharmony_ci		switch (rate) {
33862306a36Sopenharmony_ci		case 8000:
33962306a36Sopenharmony_ci			v = OPORTMXCTR1_FSSEL_8;
34062306a36Sopenharmony_ci			break;
34162306a36Sopenharmony_ci		case 11025:
34262306a36Sopenharmony_ci			v = OPORTMXCTR1_FSSEL_11_025;
34362306a36Sopenharmony_ci			break;
34462306a36Sopenharmony_ci		case 12000:
34562306a36Sopenharmony_ci			v = OPORTMXCTR1_FSSEL_12;
34662306a36Sopenharmony_ci			break;
34762306a36Sopenharmony_ci		case 16000:
34862306a36Sopenharmony_ci			v = OPORTMXCTR1_FSSEL_16;
34962306a36Sopenharmony_ci			break;
35062306a36Sopenharmony_ci		case 22050:
35162306a36Sopenharmony_ci			v = OPORTMXCTR1_FSSEL_22_05;
35262306a36Sopenharmony_ci			break;
35362306a36Sopenharmony_ci		case 24000:
35462306a36Sopenharmony_ci			v = OPORTMXCTR1_FSSEL_24;
35562306a36Sopenharmony_ci			break;
35662306a36Sopenharmony_ci		case 32000:
35762306a36Sopenharmony_ci			v = OPORTMXCTR1_FSSEL_32;
35862306a36Sopenharmony_ci			break;
35962306a36Sopenharmony_ci		case 44100:
36062306a36Sopenharmony_ci			v = OPORTMXCTR1_FSSEL_44_1;
36162306a36Sopenharmony_ci			break;
36262306a36Sopenharmony_ci		case 48000:
36362306a36Sopenharmony_ci			v = OPORTMXCTR1_FSSEL_48;
36462306a36Sopenharmony_ci			break;
36562306a36Sopenharmony_ci		case 88200:
36662306a36Sopenharmony_ci			v = OPORTMXCTR1_FSSEL_88_2;
36762306a36Sopenharmony_ci			break;
36862306a36Sopenharmony_ci		case 96000:
36962306a36Sopenharmony_ci			v = OPORTMXCTR1_FSSEL_96;
37062306a36Sopenharmony_ci			break;
37162306a36Sopenharmony_ci		case 176400:
37262306a36Sopenharmony_ci			v = OPORTMXCTR1_FSSEL_176_4;
37362306a36Sopenharmony_ci			break;
37462306a36Sopenharmony_ci		case 192000:
37562306a36Sopenharmony_ci			v = OPORTMXCTR1_FSSEL_192;
37662306a36Sopenharmony_ci			break;
37762306a36Sopenharmony_ci		default:
37862306a36Sopenharmony_ci			dev_err(dev, "Rate not supported(%d)\n", rate);
37962306a36Sopenharmony_ci			return -EINVAL;
38062306a36Sopenharmony_ci		}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci		regmap_update_bits(r, OPORTMXCTR1(sub->swm->oport.map),
38362306a36Sopenharmony_ci				   OPORTMXCTR1_FSSEL_MASK, v);
38462306a36Sopenharmony_ci	} else {
38562306a36Sopenharmony_ci		switch (rate) {
38662306a36Sopenharmony_ci		case 8000:
38762306a36Sopenharmony_ci			v = IPORTMXCTR1_FSSEL_8;
38862306a36Sopenharmony_ci			break;
38962306a36Sopenharmony_ci		case 11025:
39062306a36Sopenharmony_ci			v = IPORTMXCTR1_FSSEL_11_025;
39162306a36Sopenharmony_ci			break;
39262306a36Sopenharmony_ci		case 12000:
39362306a36Sopenharmony_ci			v = IPORTMXCTR1_FSSEL_12;
39462306a36Sopenharmony_ci			break;
39562306a36Sopenharmony_ci		case 16000:
39662306a36Sopenharmony_ci			v = IPORTMXCTR1_FSSEL_16;
39762306a36Sopenharmony_ci			break;
39862306a36Sopenharmony_ci		case 22050:
39962306a36Sopenharmony_ci			v = IPORTMXCTR1_FSSEL_22_05;
40062306a36Sopenharmony_ci			break;
40162306a36Sopenharmony_ci		case 24000:
40262306a36Sopenharmony_ci			v = IPORTMXCTR1_FSSEL_24;
40362306a36Sopenharmony_ci			break;
40462306a36Sopenharmony_ci		case 32000:
40562306a36Sopenharmony_ci			v = IPORTMXCTR1_FSSEL_32;
40662306a36Sopenharmony_ci			break;
40762306a36Sopenharmony_ci		case 44100:
40862306a36Sopenharmony_ci			v = IPORTMXCTR1_FSSEL_44_1;
40962306a36Sopenharmony_ci			break;
41062306a36Sopenharmony_ci		case 48000:
41162306a36Sopenharmony_ci			v = IPORTMXCTR1_FSSEL_48;
41262306a36Sopenharmony_ci			break;
41362306a36Sopenharmony_ci		case 88200:
41462306a36Sopenharmony_ci			v = IPORTMXCTR1_FSSEL_88_2;
41562306a36Sopenharmony_ci			break;
41662306a36Sopenharmony_ci		case 96000:
41762306a36Sopenharmony_ci			v = IPORTMXCTR1_FSSEL_96;
41862306a36Sopenharmony_ci			break;
41962306a36Sopenharmony_ci		case 176400:
42062306a36Sopenharmony_ci			v = IPORTMXCTR1_FSSEL_176_4;
42162306a36Sopenharmony_ci			break;
42262306a36Sopenharmony_ci		case 192000:
42362306a36Sopenharmony_ci			v = IPORTMXCTR1_FSSEL_192;
42462306a36Sopenharmony_ci			break;
42562306a36Sopenharmony_ci		default:
42662306a36Sopenharmony_ci			dev_err(dev, "Rate not supported(%d)\n", rate);
42762306a36Sopenharmony_ci			return -EINVAL;
42862306a36Sopenharmony_ci		}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci		regmap_update_bits(r, IPORTMXCTR1(sub->swm->iport.map),
43162306a36Sopenharmony_ci				   IPORTMXCTR1_FSSEL_MASK, v);
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	return 0;
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci/**
43862306a36Sopenharmony_ci * aio_port_set_fmt - set format of I2S data
43962306a36Sopenharmony_ci * @sub: the AIO substream pointer, PCM substream only
44062306a36Sopenharmony_ci * This parameter has no effect if substream is I2S or PCM.
44162306a36Sopenharmony_ci *
44262306a36Sopenharmony_ci * Set suitable I2S format settings to input/output port block of AIO.
44362306a36Sopenharmony_ci * Parameter is specified by set_fmt().
44462306a36Sopenharmony_ci *
44562306a36Sopenharmony_ci * This function may return error if non-PCM substream.
44662306a36Sopenharmony_ci *
44762306a36Sopenharmony_ci * Return: Zero if successful, otherwise a negative value on error.
44862306a36Sopenharmony_ci */
44962306a36Sopenharmony_cistatic int aio_port_set_fmt(struct uniphier_aio_sub *sub)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
45262306a36Sopenharmony_ci	struct device *dev = &sub->aio->chip->pdev->dev;
45362306a36Sopenharmony_ci	u32 v;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	if (sub->swm->dir == PORT_DIR_OUTPUT) {
45662306a36Sopenharmony_ci		switch (sub->aio->fmt) {
45762306a36Sopenharmony_ci		case SND_SOC_DAIFMT_LEFT_J:
45862306a36Sopenharmony_ci			v = OPORTMXCTR1_I2SLRSEL_LEFT;
45962306a36Sopenharmony_ci			break;
46062306a36Sopenharmony_ci		case SND_SOC_DAIFMT_RIGHT_J:
46162306a36Sopenharmony_ci			v = OPORTMXCTR1_I2SLRSEL_RIGHT;
46262306a36Sopenharmony_ci			break;
46362306a36Sopenharmony_ci		case SND_SOC_DAIFMT_I2S:
46462306a36Sopenharmony_ci			v = OPORTMXCTR1_I2SLRSEL_I2S;
46562306a36Sopenharmony_ci			break;
46662306a36Sopenharmony_ci		default:
46762306a36Sopenharmony_ci			dev_err(dev, "Format is not supported(%d)\n",
46862306a36Sopenharmony_ci				sub->aio->fmt);
46962306a36Sopenharmony_ci			return -EINVAL;
47062306a36Sopenharmony_ci		}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci		v |= OPORTMXCTR1_OUTBITSEL_24;
47362306a36Sopenharmony_ci		regmap_update_bits(r, OPORTMXCTR1(sub->swm->oport.map),
47462306a36Sopenharmony_ci				   OPORTMXCTR1_I2SLRSEL_MASK |
47562306a36Sopenharmony_ci				   OPORTMXCTR1_OUTBITSEL_MASK, v);
47662306a36Sopenharmony_ci	} else {
47762306a36Sopenharmony_ci		switch (sub->aio->fmt) {
47862306a36Sopenharmony_ci		case SND_SOC_DAIFMT_LEFT_J:
47962306a36Sopenharmony_ci			v = IPORTMXCTR1_LRSEL_LEFT;
48062306a36Sopenharmony_ci			break;
48162306a36Sopenharmony_ci		case SND_SOC_DAIFMT_RIGHT_J:
48262306a36Sopenharmony_ci			v = IPORTMXCTR1_LRSEL_RIGHT;
48362306a36Sopenharmony_ci			break;
48462306a36Sopenharmony_ci		case SND_SOC_DAIFMT_I2S:
48562306a36Sopenharmony_ci			v = IPORTMXCTR1_LRSEL_I2S;
48662306a36Sopenharmony_ci			break;
48762306a36Sopenharmony_ci		default:
48862306a36Sopenharmony_ci			dev_err(dev, "Format is not supported(%d)\n",
48962306a36Sopenharmony_ci				sub->aio->fmt);
49062306a36Sopenharmony_ci			return -EINVAL;
49162306a36Sopenharmony_ci		}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci		v |= IPORTMXCTR1_OUTBITSEL_24 |
49462306a36Sopenharmony_ci			IPORTMXCTR1_CHSEL_ALL;
49562306a36Sopenharmony_ci		regmap_update_bits(r, IPORTMXCTR1(sub->swm->iport.map),
49662306a36Sopenharmony_ci				   IPORTMXCTR1_LRSEL_MASK |
49762306a36Sopenharmony_ci				   IPORTMXCTR1_OUTBITSEL_MASK |
49862306a36Sopenharmony_ci				   IPORTMXCTR1_CHSEL_MASK, v);
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	return 0;
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci/**
50562306a36Sopenharmony_ci * aio_port_set_clk - set clock and divider of AIO port block
50662306a36Sopenharmony_ci * @sub: the AIO substream pointer
50762306a36Sopenharmony_ci *
50862306a36Sopenharmony_ci * Set suitable PLL clock divider and relational settings to
50962306a36Sopenharmony_ci * input/output port block of AIO. Parameters are specified by
51062306a36Sopenharmony_ci * set_sysclk() and set_pll().
51162306a36Sopenharmony_ci *
51262306a36Sopenharmony_ci * Return: Zero if successful, otherwise a negative value on error.
51362306a36Sopenharmony_ci */
51462306a36Sopenharmony_cistatic int aio_port_set_clk(struct uniphier_aio_sub *sub)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	struct uniphier_aio_chip *chip = sub->aio->chip;
51762306a36Sopenharmony_ci	struct device *dev = &sub->aio->chip->pdev->dev;
51862306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
51962306a36Sopenharmony_ci	static const u32 v_pll[] = {
52062306a36Sopenharmony_ci		OPORTMXCTR2_ACLKSEL_A1, OPORTMXCTR2_ACLKSEL_F1,
52162306a36Sopenharmony_ci		OPORTMXCTR2_ACLKSEL_A2, OPORTMXCTR2_ACLKSEL_F2,
52262306a36Sopenharmony_ci		OPORTMXCTR2_ACLKSEL_A2PLL,
52362306a36Sopenharmony_ci		OPORTMXCTR2_ACLKSEL_RX1,
52462306a36Sopenharmony_ci	};
52562306a36Sopenharmony_ci	static const u32 v_div[] = {
52662306a36Sopenharmony_ci		OPORTMXCTR2_DACCKSEL_1_2, OPORTMXCTR2_DACCKSEL_1_3,
52762306a36Sopenharmony_ci		OPORTMXCTR2_DACCKSEL_1_1, OPORTMXCTR2_DACCKSEL_2_3,
52862306a36Sopenharmony_ci	};
52962306a36Sopenharmony_ci	u32 v;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	if (sub->swm->dir == PORT_DIR_OUTPUT) {
53262306a36Sopenharmony_ci		if (sub->swm->type == PORT_TYPE_I2S) {
53362306a36Sopenharmony_ci			if (sub->aio->pll_out >= ARRAY_SIZE(v_pll)) {
53462306a36Sopenharmony_ci				dev_err(dev, "PLL(%d) is invalid\n",
53562306a36Sopenharmony_ci					sub->aio->pll_out);
53662306a36Sopenharmony_ci				return -EINVAL;
53762306a36Sopenharmony_ci			}
53862306a36Sopenharmony_ci			if (sub->aio->plldiv >= ARRAY_SIZE(v_div)) {
53962306a36Sopenharmony_ci				dev_err(dev, "PLL divider(%d) is invalid\n",
54062306a36Sopenharmony_ci					sub->aio->plldiv);
54162306a36Sopenharmony_ci				return -EINVAL;
54262306a36Sopenharmony_ci			}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci			v = v_pll[sub->aio->pll_out] |
54562306a36Sopenharmony_ci				OPORTMXCTR2_MSSEL_MASTER |
54662306a36Sopenharmony_ci				v_div[sub->aio->plldiv];
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci			switch (chip->plls[sub->aio->pll_out].freq) {
54962306a36Sopenharmony_ci			case 0:
55062306a36Sopenharmony_ci			case 36864000:
55162306a36Sopenharmony_ci			case 33868800:
55262306a36Sopenharmony_ci				v |= OPORTMXCTR2_EXTLSIFSSEL_36;
55362306a36Sopenharmony_ci				break;
55462306a36Sopenharmony_ci			default:
55562306a36Sopenharmony_ci				v |= OPORTMXCTR2_EXTLSIFSSEL_24;
55662306a36Sopenharmony_ci				break;
55762306a36Sopenharmony_ci			}
55862306a36Sopenharmony_ci		} else if (sub->swm->type == PORT_TYPE_EVE) {
55962306a36Sopenharmony_ci			v = OPORTMXCTR2_ACLKSEL_A2PLL |
56062306a36Sopenharmony_ci				OPORTMXCTR2_MSSEL_MASTER |
56162306a36Sopenharmony_ci				OPORTMXCTR2_EXTLSIFSSEL_36 |
56262306a36Sopenharmony_ci				OPORTMXCTR2_DACCKSEL_1_2;
56362306a36Sopenharmony_ci		} else if (sub->swm->type == PORT_TYPE_SPDIF) {
56462306a36Sopenharmony_ci			if (sub->aio->pll_out >= ARRAY_SIZE(v_pll)) {
56562306a36Sopenharmony_ci				dev_err(dev, "PLL(%d) is invalid\n",
56662306a36Sopenharmony_ci					sub->aio->pll_out);
56762306a36Sopenharmony_ci				return -EINVAL;
56862306a36Sopenharmony_ci			}
56962306a36Sopenharmony_ci			v = v_pll[sub->aio->pll_out] |
57062306a36Sopenharmony_ci				OPORTMXCTR2_MSSEL_MASTER |
57162306a36Sopenharmony_ci				OPORTMXCTR2_DACCKSEL_1_2;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci			switch (chip->plls[sub->aio->pll_out].freq) {
57462306a36Sopenharmony_ci			case 0:
57562306a36Sopenharmony_ci			case 36864000:
57662306a36Sopenharmony_ci			case 33868800:
57762306a36Sopenharmony_ci				v |= OPORTMXCTR2_EXTLSIFSSEL_36;
57862306a36Sopenharmony_ci				break;
57962306a36Sopenharmony_ci			default:
58062306a36Sopenharmony_ci				v |= OPORTMXCTR2_EXTLSIFSSEL_24;
58162306a36Sopenharmony_ci				break;
58262306a36Sopenharmony_ci			}
58362306a36Sopenharmony_ci		} else {
58462306a36Sopenharmony_ci			v = OPORTMXCTR2_ACLKSEL_A1 |
58562306a36Sopenharmony_ci				OPORTMXCTR2_MSSEL_MASTER |
58662306a36Sopenharmony_ci				OPORTMXCTR2_EXTLSIFSSEL_36 |
58762306a36Sopenharmony_ci				OPORTMXCTR2_DACCKSEL_1_2;
58862306a36Sopenharmony_ci		}
58962306a36Sopenharmony_ci		regmap_write(r, OPORTMXCTR2(sub->swm->oport.map), v);
59062306a36Sopenharmony_ci	} else {
59162306a36Sopenharmony_ci		v = IPORTMXCTR2_ACLKSEL_A1 |
59262306a36Sopenharmony_ci			IPORTMXCTR2_MSSEL_SLAVE |
59362306a36Sopenharmony_ci			IPORTMXCTR2_EXTLSIFSSEL_36 |
59462306a36Sopenharmony_ci			IPORTMXCTR2_DACCKSEL_1_2;
59562306a36Sopenharmony_ci		regmap_write(r, IPORTMXCTR2(sub->swm->iport.map), v);
59662306a36Sopenharmony_ci	}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	return 0;
59962306a36Sopenharmony_ci}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci/**
60262306a36Sopenharmony_ci * aio_port_set_param - set parameters of AIO port block
60362306a36Sopenharmony_ci * @sub: the AIO substream pointer
60462306a36Sopenharmony_ci * @pass_through: Zero if sound data is LPCM, otherwise if data is not LPCM.
60562306a36Sopenharmony_ci * This parameter has no effect if substream is I2S or PCM.
60662306a36Sopenharmony_ci * @params: hardware parameters of ALSA
60762306a36Sopenharmony_ci *
60862306a36Sopenharmony_ci * Set suitable setting to input/output port block of AIO to process the
60962306a36Sopenharmony_ci * specified in params.
61062306a36Sopenharmony_ci *
61162306a36Sopenharmony_ci * Return: Zero if successful, otherwise a negative value on error.
61262306a36Sopenharmony_ci */
61362306a36Sopenharmony_ciint aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through,
61462306a36Sopenharmony_ci		       const struct snd_pcm_hw_params *params)
61562306a36Sopenharmony_ci{
61662306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
61762306a36Sopenharmony_ci	unsigned int rate;
61862306a36Sopenharmony_ci	u32 v;
61962306a36Sopenharmony_ci	int ret;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	if (!pass_through) {
62262306a36Sopenharmony_ci		if (sub->swm->type == PORT_TYPE_EVE ||
62362306a36Sopenharmony_ci		    sub->swm->type == PORT_TYPE_CONV) {
62462306a36Sopenharmony_ci			rate = 48000;
62562306a36Sopenharmony_ci		} else {
62662306a36Sopenharmony_ci			rate = params_rate(params);
62762306a36Sopenharmony_ci		}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci		ret = aio_port_set_ch(sub);
63062306a36Sopenharmony_ci		if (ret)
63162306a36Sopenharmony_ci			return ret;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci		ret = aio_port_set_rate(sub, rate);
63462306a36Sopenharmony_ci		if (ret)
63562306a36Sopenharmony_ci			return ret;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci		ret = aio_port_set_fmt(sub);
63862306a36Sopenharmony_ci		if (ret)
63962306a36Sopenharmony_ci			return ret;
64062306a36Sopenharmony_ci	}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	ret = aio_port_set_clk(sub);
64362306a36Sopenharmony_ci	if (ret)
64462306a36Sopenharmony_ci		return ret;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	if (sub->swm->dir == PORT_DIR_OUTPUT) {
64762306a36Sopenharmony_ci		if (pass_through)
64862306a36Sopenharmony_ci			v = OPORTMXCTR3_SRCSEL_STREAM |
64962306a36Sopenharmony_ci				OPORTMXCTR3_VALID_STREAM;
65062306a36Sopenharmony_ci		else
65162306a36Sopenharmony_ci			v = OPORTMXCTR3_SRCSEL_PCM |
65262306a36Sopenharmony_ci				OPORTMXCTR3_VALID_PCM;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci		v |= OPORTMXCTR3_IECTHUR_IECOUT |
65562306a36Sopenharmony_ci			OPORTMXCTR3_PMSEL_PAUSE |
65662306a36Sopenharmony_ci			OPORTMXCTR3_PMSW_MUTE_OFF;
65762306a36Sopenharmony_ci		regmap_write(r, OPORTMXCTR3(sub->swm->oport.map), v);
65862306a36Sopenharmony_ci	} else {
65962306a36Sopenharmony_ci		regmap_write(r, IPORTMXACLKSEL0EX(sub->swm->iport.map),
66062306a36Sopenharmony_ci			     IPORTMXACLKSEL0EX_ACLKSEL0EX_INTERNAL);
66162306a36Sopenharmony_ci		regmap_write(r, IPORTMXEXNOE(sub->swm->iport.map),
66262306a36Sopenharmony_ci			     IPORTMXEXNOE_PCMINOE_INPUT);
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	return 0;
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci/**
66962306a36Sopenharmony_ci * aio_port_set_enable - start or stop of AIO port block
67062306a36Sopenharmony_ci * @sub: the AIO substream pointer
67162306a36Sopenharmony_ci * @enable: zero to stop the block, otherwise to start
67262306a36Sopenharmony_ci *
67362306a36Sopenharmony_ci * Start or stop the signal input/output port block of AIO.
67462306a36Sopenharmony_ci */
67562306a36Sopenharmony_civoid aio_port_set_enable(struct uniphier_aio_sub *sub, int enable)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	if (sub->swm->dir == PORT_DIR_OUTPUT) {
68062306a36Sopenharmony_ci		regmap_write(r, OPORTMXPATH(sub->swm->oport.map),
68162306a36Sopenharmony_ci			     sub->swm->oif.map);
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci		regmap_update_bits(r, OPORTMXMASK(sub->swm->oport.map),
68462306a36Sopenharmony_ci				   OPORTMXMASK_IUDXMSK_MASK |
68562306a36Sopenharmony_ci				   OPORTMXMASK_IUXCKMSK_MASK |
68662306a36Sopenharmony_ci				   OPORTMXMASK_DXMSK_MASK |
68762306a36Sopenharmony_ci				   OPORTMXMASK_XCKMSK_MASK,
68862306a36Sopenharmony_ci				   OPORTMXMASK_IUDXMSK_OFF |
68962306a36Sopenharmony_ci				   OPORTMXMASK_IUXCKMSK_OFF |
69062306a36Sopenharmony_ci				   OPORTMXMASK_DXMSK_OFF |
69162306a36Sopenharmony_ci				   OPORTMXMASK_XCKMSK_OFF);
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci		if (enable)
69462306a36Sopenharmony_ci			regmap_write(r, AOUTENCTR0, BIT(sub->swm->oport.map));
69562306a36Sopenharmony_ci		else
69662306a36Sopenharmony_ci			regmap_write(r, AOUTENCTR1, BIT(sub->swm->oport.map));
69762306a36Sopenharmony_ci	} else {
69862306a36Sopenharmony_ci		regmap_update_bits(r, IPORTMXMASK(sub->swm->iport.map),
69962306a36Sopenharmony_ci				   IPORTMXMASK_IUXCKMSK_MASK |
70062306a36Sopenharmony_ci				   IPORTMXMASK_XCKMSK_MASK,
70162306a36Sopenharmony_ci				   IPORTMXMASK_IUXCKMSK_OFF |
70262306a36Sopenharmony_ci				   IPORTMXMASK_XCKMSK_OFF);
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci		if (enable)
70562306a36Sopenharmony_ci			regmap_update_bits(r,
70662306a36Sopenharmony_ci					   IPORTMXCTR2(sub->swm->iport.map),
70762306a36Sopenharmony_ci					   IPORTMXCTR2_REQEN_MASK,
70862306a36Sopenharmony_ci					   IPORTMXCTR2_REQEN_ENABLE);
70962306a36Sopenharmony_ci		else
71062306a36Sopenharmony_ci			regmap_update_bits(r,
71162306a36Sopenharmony_ci					   IPORTMXCTR2(sub->swm->iport.map),
71262306a36Sopenharmony_ci					   IPORTMXCTR2_REQEN_MASK,
71362306a36Sopenharmony_ci					   IPORTMXCTR2_REQEN_DISABLE);
71462306a36Sopenharmony_ci	}
71562306a36Sopenharmony_ci}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci/**
71862306a36Sopenharmony_ci * aio_port_get_volume - get volume of AIO port block
71962306a36Sopenharmony_ci * @sub: the AIO substream pointer
72062306a36Sopenharmony_ci *
72162306a36Sopenharmony_ci * Return: current volume, range is 0x0000 - 0xffff
72262306a36Sopenharmony_ci */
72362306a36Sopenharmony_ciint aio_port_get_volume(struct uniphier_aio_sub *sub)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
72662306a36Sopenharmony_ci	u32 v;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	regmap_read(r, OPORTMXTYVOLGAINSTATUS(sub->swm->oport.map, 0), &v);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	return FIELD_GET(OPORTMXTYVOLGAINSTATUS_CUR_MASK, v);
73162306a36Sopenharmony_ci}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci/**
73462306a36Sopenharmony_ci * aio_port_set_volume - set volume of AIO port block
73562306a36Sopenharmony_ci * @sub: the AIO substream pointer
73662306a36Sopenharmony_ci * @vol: target volume, range is 0x0000 - 0xffff.
73762306a36Sopenharmony_ci *
73862306a36Sopenharmony_ci * Change digital volume and perfome fade-out/fade-in effect for specified
73962306a36Sopenharmony_ci * output slot of port. Gained PCM value can calculate as the following:
74062306a36Sopenharmony_ci *   Gained = Original * vol / 0x4000
74162306a36Sopenharmony_ci */
74262306a36Sopenharmony_civoid aio_port_set_volume(struct uniphier_aio_sub *sub, int vol)
74362306a36Sopenharmony_ci{
74462306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
74562306a36Sopenharmony_ci	int oport_map = sub->swm->oport.map;
74662306a36Sopenharmony_ci	int cur, diff, slope = 0, fs;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	if (sub->swm->dir == PORT_DIR_INPUT)
74962306a36Sopenharmony_ci		return;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	cur = aio_port_get_volume(sub);
75262306a36Sopenharmony_ci	diff = abs(vol - cur);
75362306a36Sopenharmony_ci	fs = params_rate(&sub->params);
75462306a36Sopenharmony_ci	if (fs)
75562306a36Sopenharmony_ci		slope = diff / AUD_VOL_FADE_TIME * 1000 / fs;
75662306a36Sopenharmony_ci	slope = max(1, slope);
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	regmap_update_bits(r, OPORTMXTYVOLPARA1(oport_map, 0),
75962306a36Sopenharmony_ci			   OPORTMXTYVOLPARA1_SLOPEU_MASK, slope << 16);
76062306a36Sopenharmony_ci	regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
76162306a36Sopenharmony_ci			   OPORTMXTYVOLPARA2_TARGET_MASK, vol);
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	if (cur < vol)
76462306a36Sopenharmony_ci		regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
76562306a36Sopenharmony_ci				   OPORTMXTYVOLPARA2_FADE_MASK,
76662306a36Sopenharmony_ci				   OPORTMXTYVOLPARA2_FADE_FADEIN);
76762306a36Sopenharmony_ci	else
76862306a36Sopenharmony_ci		regmap_update_bits(r, OPORTMXTYVOLPARA2(oport_map, 0),
76962306a36Sopenharmony_ci				   OPORTMXTYVOLPARA2_FADE_MASK,
77062306a36Sopenharmony_ci				   OPORTMXTYVOLPARA2_FADE_FADEOUT);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	regmap_write(r, AOUTFADECTR0, BIT(oport_map));
77362306a36Sopenharmony_ci}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci/**
77662306a36Sopenharmony_ci * aio_if_set_param - set parameters of AIO DMA I/F block
77762306a36Sopenharmony_ci * @sub: the AIO substream pointer
77862306a36Sopenharmony_ci * @pass_through: Zero if sound data is LPCM, otherwise if data is not LPCM.
77962306a36Sopenharmony_ci * This parameter has no effect if substream is I2S or PCM.
78062306a36Sopenharmony_ci *
78162306a36Sopenharmony_ci * Set suitable setting to DMA interface block of AIO to process the
78262306a36Sopenharmony_ci * specified in settings.
78362306a36Sopenharmony_ci *
78462306a36Sopenharmony_ci * Return: Zero if successful, otherwise a negative value on error.
78562306a36Sopenharmony_ci */
78662306a36Sopenharmony_ciint aio_if_set_param(struct uniphier_aio_sub *sub, int pass_through)
78762306a36Sopenharmony_ci{
78862306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
78962306a36Sopenharmony_ci	u32 memfmt, v;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	if (sub->swm->dir == PORT_DIR_OUTPUT) {
79262306a36Sopenharmony_ci		if (pass_through) {
79362306a36Sopenharmony_ci			v = PBOUTMXCTR0_ENDIAN_0123 |
79462306a36Sopenharmony_ci				PBOUTMXCTR0_MEMFMT_STREAM;
79562306a36Sopenharmony_ci		} else {
79662306a36Sopenharmony_ci			switch (params_channels(&sub->params)) {
79762306a36Sopenharmony_ci			case 2:
79862306a36Sopenharmony_ci				memfmt = PBOUTMXCTR0_MEMFMT_2CH;
79962306a36Sopenharmony_ci				break;
80062306a36Sopenharmony_ci			case 6:
80162306a36Sopenharmony_ci				memfmt = PBOUTMXCTR0_MEMFMT_6CH;
80262306a36Sopenharmony_ci				break;
80362306a36Sopenharmony_ci			case 8:
80462306a36Sopenharmony_ci				memfmt = PBOUTMXCTR0_MEMFMT_8CH;
80562306a36Sopenharmony_ci				break;
80662306a36Sopenharmony_ci			default:
80762306a36Sopenharmony_ci				return -EINVAL;
80862306a36Sopenharmony_ci			}
80962306a36Sopenharmony_ci			v = PBOUTMXCTR0_ENDIAN_3210 | memfmt;
81062306a36Sopenharmony_ci		}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci		regmap_write(r, PBOUTMXCTR0(sub->swm->oif.map), v);
81362306a36Sopenharmony_ci		regmap_write(r, PBOUTMXCTR1(sub->swm->oif.map), 0);
81462306a36Sopenharmony_ci	} else {
81562306a36Sopenharmony_ci		regmap_write(r, PBINMXCTR(sub->swm->iif.map),
81662306a36Sopenharmony_ci			     PBINMXCTR_NCONNECT_CONNECT |
81762306a36Sopenharmony_ci			     PBINMXCTR_INOUTSEL_IN |
81862306a36Sopenharmony_ci			     (sub->swm->iport.map << PBINMXCTR_PBINSEL_SHIFT) |
81962306a36Sopenharmony_ci			     PBINMXCTR_ENDIAN_3210 |
82062306a36Sopenharmony_ci			     PBINMXCTR_MEMFMT_D0);
82162306a36Sopenharmony_ci	}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	return 0;
82462306a36Sopenharmony_ci}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci/**
82762306a36Sopenharmony_ci * aio_oport_set_stream_type - set parameters of AIO playback port block
82862306a36Sopenharmony_ci * @sub: the AIO substream pointer
82962306a36Sopenharmony_ci * @pc: Pc type of IEC61937
83062306a36Sopenharmony_ci *
83162306a36Sopenharmony_ci * Set special setting to output port block of AIO to output the stream
83262306a36Sopenharmony_ci * via S/PDIF.
83362306a36Sopenharmony_ci *
83462306a36Sopenharmony_ci * Return: Zero if successful, otherwise a negative value on error.
83562306a36Sopenharmony_ci */
83662306a36Sopenharmony_ciint aio_oport_set_stream_type(struct uniphier_aio_sub *sub,
83762306a36Sopenharmony_ci			      enum IEC61937_PC pc)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
84062306a36Sopenharmony_ci	u32 repet = 0, pause = OPORTMXPAUDAT_PAUSEPC_CMN;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	switch (pc) {
84362306a36Sopenharmony_ci	case IEC61937_PC_AC3:
84462306a36Sopenharmony_ci		repet = OPORTMXREPET_STRLENGTH_AC3 |
84562306a36Sopenharmony_ci			OPORTMXREPET_PMLENGTH_AC3;
84662306a36Sopenharmony_ci		pause |= OPORTMXPAUDAT_PAUSEPD_AC3;
84762306a36Sopenharmony_ci		break;
84862306a36Sopenharmony_ci	case IEC61937_PC_MPA:
84962306a36Sopenharmony_ci		repet = OPORTMXREPET_STRLENGTH_MPA |
85062306a36Sopenharmony_ci			OPORTMXREPET_PMLENGTH_MPA;
85162306a36Sopenharmony_ci		pause |= OPORTMXPAUDAT_PAUSEPD_MPA;
85262306a36Sopenharmony_ci		break;
85362306a36Sopenharmony_ci	case IEC61937_PC_MP3:
85462306a36Sopenharmony_ci		repet = OPORTMXREPET_STRLENGTH_MP3 |
85562306a36Sopenharmony_ci			OPORTMXREPET_PMLENGTH_MP3;
85662306a36Sopenharmony_ci		pause |= OPORTMXPAUDAT_PAUSEPD_MP3;
85762306a36Sopenharmony_ci		break;
85862306a36Sopenharmony_ci	case IEC61937_PC_DTS1:
85962306a36Sopenharmony_ci		repet = OPORTMXREPET_STRLENGTH_DTS1 |
86062306a36Sopenharmony_ci			OPORTMXREPET_PMLENGTH_DTS1;
86162306a36Sopenharmony_ci		pause |= OPORTMXPAUDAT_PAUSEPD_DTS1;
86262306a36Sopenharmony_ci		break;
86362306a36Sopenharmony_ci	case IEC61937_PC_DTS2:
86462306a36Sopenharmony_ci		repet = OPORTMXREPET_STRLENGTH_DTS2 |
86562306a36Sopenharmony_ci			OPORTMXREPET_PMLENGTH_DTS2;
86662306a36Sopenharmony_ci		pause |= OPORTMXPAUDAT_PAUSEPD_DTS2;
86762306a36Sopenharmony_ci		break;
86862306a36Sopenharmony_ci	case IEC61937_PC_DTS3:
86962306a36Sopenharmony_ci		repet = OPORTMXREPET_STRLENGTH_DTS3 |
87062306a36Sopenharmony_ci			OPORTMXREPET_PMLENGTH_DTS3;
87162306a36Sopenharmony_ci		pause |= OPORTMXPAUDAT_PAUSEPD_DTS3;
87262306a36Sopenharmony_ci		break;
87362306a36Sopenharmony_ci	case IEC61937_PC_AAC:
87462306a36Sopenharmony_ci		repet = OPORTMXREPET_STRLENGTH_AAC |
87562306a36Sopenharmony_ci			OPORTMXREPET_PMLENGTH_AAC;
87662306a36Sopenharmony_ci		pause |= OPORTMXPAUDAT_PAUSEPD_AAC;
87762306a36Sopenharmony_ci		break;
87862306a36Sopenharmony_ci	case IEC61937_PC_PAUSE:
87962306a36Sopenharmony_ci		/* Do nothing */
88062306a36Sopenharmony_ci		break;
88162306a36Sopenharmony_ci	}
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	regmap_write(r, OPORTMXREPET(sub->swm->oport.map), repet);
88462306a36Sopenharmony_ci	regmap_write(r, OPORTMXPAUDAT(sub->swm->oport.map), pause);
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	return 0;
88762306a36Sopenharmony_ci}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci/**
89062306a36Sopenharmony_ci * aio_src_reset - reset AIO SRC block
89162306a36Sopenharmony_ci * @sub: the AIO substream pointer
89262306a36Sopenharmony_ci *
89362306a36Sopenharmony_ci * Resets the digital signal input/output port with sampling rate converter
89462306a36Sopenharmony_ci * block of AIO.
89562306a36Sopenharmony_ci * This function has no effect if substream is not supported rate converter.
89662306a36Sopenharmony_ci */
89762306a36Sopenharmony_civoid aio_src_reset(struct uniphier_aio_sub *sub)
89862306a36Sopenharmony_ci{
89962306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	if (sub->swm->dir != PORT_DIR_OUTPUT)
90262306a36Sopenharmony_ci		return;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	regmap_write(r, AOUTSRCRSTCTR0, BIT(sub->swm->oport.map));
90562306a36Sopenharmony_ci	regmap_write(r, AOUTSRCRSTCTR1, BIT(sub->swm->oport.map));
90662306a36Sopenharmony_ci}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci/**
90962306a36Sopenharmony_ci * aio_src_set_param - set parameters of AIO SRC block
91062306a36Sopenharmony_ci * @sub: the AIO substream pointer
91162306a36Sopenharmony_ci * @params: hardware parameters of ALSA
91262306a36Sopenharmony_ci *
91362306a36Sopenharmony_ci * Set suitable setting to input/output port with sampling rate converter
91462306a36Sopenharmony_ci * block of AIO to process the specified in params.
91562306a36Sopenharmony_ci * This function has no effect if substream is not supported rate converter.
91662306a36Sopenharmony_ci *
91762306a36Sopenharmony_ci * Return: Zero if successful, otherwise a negative value on error.
91862306a36Sopenharmony_ci */
91962306a36Sopenharmony_ciint aio_src_set_param(struct uniphier_aio_sub *sub,
92062306a36Sopenharmony_ci		      const struct snd_pcm_hw_params *params)
92162306a36Sopenharmony_ci{
92262306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
92362306a36Sopenharmony_ci	u32 v;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	if (sub->swm->dir != PORT_DIR_OUTPUT)
92662306a36Sopenharmony_ci		return 0;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	regmap_write(r, OPORTMXSRC1CTR(sub->swm->oport.map),
92962306a36Sopenharmony_ci		     OPORTMXSRC1CTR_THMODE_SRC |
93062306a36Sopenharmony_ci		     OPORTMXSRC1CTR_SRCPATH_CALC |
93162306a36Sopenharmony_ci		     OPORTMXSRC1CTR_SYNC_ASYNC |
93262306a36Sopenharmony_ci		     OPORTMXSRC1CTR_FSIIPSEL_INNER |
93362306a36Sopenharmony_ci		     OPORTMXSRC1CTR_FSISEL_ACLK);
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	switch (params_rate(params)) {
93662306a36Sopenharmony_ci	default:
93762306a36Sopenharmony_ci	case 48000:
93862306a36Sopenharmony_ci		v = OPORTMXRATE_I_ACLKSEL_APLLA1 |
93962306a36Sopenharmony_ci			OPORTMXRATE_I_MCKSEL_36 |
94062306a36Sopenharmony_ci			OPORTMXRATE_I_FSSEL_48;
94162306a36Sopenharmony_ci		break;
94262306a36Sopenharmony_ci	case 44100:
94362306a36Sopenharmony_ci		v = OPORTMXRATE_I_ACLKSEL_APLLA2 |
94462306a36Sopenharmony_ci			OPORTMXRATE_I_MCKSEL_33 |
94562306a36Sopenharmony_ci			OPORTMXRATE_I_FSSEL_44_1;
94662306a36Sopenharmony_ci		break;
94762306a36Sopenharmony_ci	case 32000:
94862306a36Sopenharmony_ci		v = OPORTMXRATE_I_ACLKSEL_APLLA1 |
94962306a36Sopenharmony_ci			OPORTMXRATE_I_MCKSEL_36 |
95062306a36Sopenharmony_ci			OPORTMXRATE_I_FSSEL_32;
95162306a36Sopenharmony_ci		break;
95262306a36Sopenharmony_ci	}
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	regmap_write(r, OPORTMXRATE_I(sub->swm->oport.map),
95562306a36Sopenharmony_ci		     v | OPORTMXRATE_I_ACLKSRC_APLL |
95662306a36Sopenharmony_ci		     OPORTMXRATE_I_LRCKSTP_STOP);
95762306a36Sopenharmony_ci	regmap_update_bits(r, OPORTMXRATE_I(sub->swm->oport.map),
95862306a36Sopenharmony_ci			   OPORTMXRATE_I_LRCKSTP_MASK,
95962306a36Sopenharmony_ci			   OPORTMXRATE_I_LRCKSTP_START);
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	return 0;
96262306a36Sopenharmony_ci}
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ciint aio_srcif_set_param(struct uniphier_aio_sub *sub)
96562306a36Sopenharmony_ci{
96662306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	regmap_write(r, PBINMXCTR(sub->swm->iif.map),
96962306a36Sopenharmony_ci		     PBINMXCTR_NCONNECT_CONNECT |
97062306a36Sopenharmony_ci		     PBINMXCTR_INOUTSEL_OUT |
97162306a36Sopenharmony_ci		     (sub->swm->oport.map << PBINMXCTR_PBINSEL_SHIFT) |
97262306a36Sopenharmony_ci		     PBINMXCTR_ENDIAN_3210 |
97362306a36Sopenharmony_ci		     PBINMXCTR_MEMFMT_D0);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	return 0;
97662306a36Sopenharmony_ci}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ciint aio_srcch_set_param(struct uniphier_aio_sub *sub)
97962306a36Sopenharmony_ci{
98062306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	regmap_write(r, CDA2D_CHMXCTRL1(sub->swm->och.map),
98362306a36Sopenharmony_ci		     CDA2D_CHMXCTRL1_INDSIZE_INFINITE);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	regmap_write(r, CDA2D_CHMXSRCAMODE(sub->swm->och.map),
98662306a36Sopenharmony_ci		     CDA2D_CHMXAMODE_ENDIAN_3210 |
98762306a36Sopenharmony_ci		     CDA2D_CHMXAMODE_AUPDT_FIX |
98862306a36Sopenharmony_ci		     CDA2D_CHMXAMODE_TYPE_NORMAL);
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	regmap_write(r, CDA2D_CHMXDSTAMODE(sub->swm->och.map),
99162306a36Sopenharmony_ci		     CDA2D_CHMXAMODE_ENDIAN_3210 |
99262306a36Sopenharmony_ci		     CDA2D_CHMXAMODE_AUPDT_INC |
99362306a36Sopenharmony_ci		     CDA2D_CHMXAMODE_TYPE_RING |
99462306a36Sopenharmony_ci		     (sub->swm->och.map << CDA2D_CHMXAMODE_RSSEL_SHIFT));
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	return 0;
99762306a36Sopenharmony_ci}
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_civoid aio_srcch_set_enable(struct uniphier_aio_sub *sub, int enable)
100062306a36Sopenharmony_ci{
100162306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
100262306a36Sopenharmony_ci	u32 v;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	if (enable)
100562306a36Sopenharmony_ci		v = CDA2D_STRT0_STOP_START;
100662306a36Sopenharmony_ci	else
100762306a36Sopenharmony_ci		v = CDA2D_STRT0_STOP_STOP;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	regmap_write(r, CDA2D_STRT0,
101062306a36Sopenharmony_ci		     v | BIT(sub->swm->och.map));
101162306a36Sopenharmony_ci}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ciint aiodma_ch_set_param(struct uniphier_aio_sub *sub)
101462306a36Sopenharmony_ci{
101562306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
101662306a36Sopenharmony_ci	u32 v;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	regmap_write(r, CDA2D_CHMXCTRL1(sub->swm->ch.map),
101962306a36Sopenharmony_ci		     CDA2D_CHMXCTRL1_INDSIZE_INFINITE);
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	v = CDA2D_CHMXAMODE_ENDIAN_3210 |
102262306a36Sopenharmony_ci		CDA2D_CHMXAMODE_AUPDT_INC |
102362306a36Sopenharmony_ci		CDA2D_CHMXAMODE_TYPE_NORMAL |
102462306a36Sopenharmony_ci		(sub->swm->rb.map << CDA2D_CHMXAMODE_RSSEL_SHIFT);
102562306a36Sopenharmony_ci	if (sub->swm->dir == PORT_DIR_OUTPUT)
102662306a36Sopenharmony_ci		regmap_write(r, CDA2D_CHMXSRCAMODE(sub->swm->ch.map), v);
102762306a36Sopenharmony_ci	else
102862306a36Sopenharmony_ci		regmap_write(r, CDA2D_CHMXDSTAMODE(sub->swm->ch.map), v);
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	return 0;
103162306a36Sopenharmony_ci}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_civoid aiodma_ch_set_enable(struct uniphier_aio_sub *sub, int enable)
103462306a36Sopenharmony_ci{
103562306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	if (enable) {
103862306a36Sopenharmony_ci		regmap_write(r, CDA2D_STRT0,
103962306a36Sopenharmony_ci			     CDA2D_STRT0_STOP_START | BIT(sub->swm->ch.map));
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci		regmap_update_bits(r, INTRBIM(0),
104262306a36Sopenharmony_ci				   BIT(sub->swm->rb.map),
104362306a36Sopenharmony_ci				   BIT(sub->swm->rb.map));
104462306a36Sopenharmony_ci	} else {
104562306a36Sopenharmony_ci		regmap_write(r, CDA2D_STRT0,
104662306a36Sopenharmony_ci			     CDA2D_STRT0_STOP_STOP | BIT(sub->swm->ch.map));
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci		regmap_update_bits(r, INTRBIM(0),
104962306a36Sopenharmony_ci				   BIT(sub->swm->rb.map),
105062306a36Sopenharmony_ci				   0);
105162306a36Sopenharmony_ci	}
105262306a36Sopenharmony_ci}
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_cistatic u64 aiodma_rb_get_rp(struct uniphier_aio_sub *sub)
105562306a36Sopenharmony_ci{
105662306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
105762306a36Sopenharmony_ci	u32 pos_u, pos_l;
105862306a36Sopenharmony_ci	int i;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	regmap_write(r, CDA2D_RDPTRLOAD,
106162306a36Sopenharmony_ci		     CDA2D_RDPTRLOAD_LSFLAG_STORE | BIT(sub->swm->rb.map));
106262306a36Sopenharmony_ci	/* Wait for setup */
106362306a36Sopenharmony_ci	for (i = 0; i < 6; i++)
106462306a36Sopenharmony_ci		regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &pos_l);
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &pos_l);
106762306a36Sopenharmony_ci	regmap_read(r, CDA2D_RBMXRDPTRU(sub->swm->rb.map), &pos_u);
106862306a36Sopenharmony_ci	pos_u = FIELD_GET(CDA2D_RBMXPTRU_PTRU_MASK, pos_u);
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	return ((u64)pos_u << 32) | pos_l;
107162306a36Sopenharmony_ci}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_cistatic void aiodma_rb_set_rp(struct uniphier_aio_sub *sub, u64 pos)
107462306a36Sopenharmony_ci{
107562306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
107662306a36Sopenharmony_ci	u32 tmp;
107762306a36Sopenharmony_ci	int i;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	regmap_write(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), (u32)pos);
108062306a36Sopenharmony_ci	regmap_write(r, CDA2D_RBMXRDPTRU(sub->swm->rb.map), (u32)(pos >> 32));
108162306a36Sopenharmony_ci	regmap_write(r, CDA2D_RDPTRLOAD, BIT(sub->swm->rb.map));
108262306a36Sopenharmony_ci	/* Wait for setup */
108362306a36Sopenharmony_ci	for (i = 0; i < 6; i++)
108462306a36Sopenharmony_ci		regmap_read(r, CDA2D_RBMXRDPTR(sub->swm->rb.map), &tmp);
108562306a36Sopenharmony_ci}
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_cistatic u64 aiodma_rb_get_wp(struct uniphier_aio_sub *sub)
108862306a36Sopenharmony_ci{
108962306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
109062306a36Sopenharmony_ci	u32 pos_u, pos_l;
109162306a36Sopenharmony_ci	int i;
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	regmap_write(r, CDA2D_WRPTRLOAD,
109462306a36Sopenharmony_ci		     CDA2D_WRPTRLOAD_LSFLAG_STORE | BIT(sub->swm->rb.map));
109562306a36Sopenharmony_ci	/* Wait for setup */
109662306a36Sopenharmony_ci	for (i = 0; i < 6; i++)
109762306a36Sopenharmony_ci		regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &pos_l);
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &pos_l);
110062306a36Sopenharmony_ci	regmap_read(r, CDA2D_RBMXWRPTRU(sub->swm->rb.map), &pos_u);
110162306a36Sopenharmony_ci	pos_u = FIELD_GET(CDA2D_RBMXPTRU_PTRU_MASK, pos_u);
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	return ((u64)pos_u << 32) | pos_l;
110462306a36Sopenharmony_ci}
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_cistatic void aiodma_rb_set_wp(struct uniphier_aio_sub *sub, u64 pos)
110762306a36Sopenharmony_ci{
110862306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
110962306a36Sopenharmony_ci	u32 tmp;
111062306a36Sopenharmony_ci	int i;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	regmap_write(r, CDA2D_RBMXWRPTR(sub->swm->rb.map),
111362306a36Sopenharmony_ci		     lower_32_bits(pos));
111462306a36Sopenharmony_ci	regmap_write(r, CDA2D_RBMXWRPTRU(sub->swm->rb.map),
111562306a36Sopenharmony_ci		     upper_32_bits(pos));
111662306a36Sopenharmony_ci	regmap_write(r, CDA2D_WRPTRLOAD, BIT(sub->swm->rb.map));
111762306a36Sopenharmony_ci	/* Wait for setup */
111862306a36Sopenharmony_ci	for (i = 0; i < 6; i++)
111962306a36Sopenharmony_ci		regmap_read(r, CDA2D_RBMXWRPTR(sub->swm->rb.map), &tmp);
112062306a36Sopenharmony_ci}
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ciint aiodma_rb_set_threshold(struct uniphier_aio_sub *sub, u64 size, u32 th)
112362306a36Sopenharmony_ci{
112462306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	if (size <= th)
112762306a36Sopenharmony_ci		return -EINVAL;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	regmap_write(r, CDA2D_RBMXBTH(sub->swm->rb.map), th);
113062306a36Sopenharmony_ci	regmap_write(r, CDA2D_RBMXRTH(sub->swm->rb.map), th);
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	return 0;
113362306a36Sopenharmony_ci}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ciint aiodma_rb_set_buffer(struct uniphier_aio_sub *sub, u64 start, u64 end,
113662306a36Sopenharmony_ci			 int period)
113762306a36Sopenharmony_ci{
113862306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
113962306a36Sopenharmony_ci	u64 size = end - start;
114062306a36Sopenharmony_ci	int ret;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	if (end < start || period < 0)
114362306a36Sopenharmony_ci		return -EINVAL;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	regmap_write(r, CDA2D_RBMXCNFG(sub->swm->rb.map), 0);
114662306a36Sopenharmony_ci	regmap_write(r, CDA2D_RBMXBGNADRS(sub->swm->rb.map),
114762306a36Sopenharmony_ci		     lower_32_bits(start));
114862306a36Sopenharmony_ci	regmap_write(r, CDA2D_RBMXBGNADRSU(sub->swm->rb.map),
114962306a36Sopenharmony_ci		     upper_32_bits(start));
115062306a36Sopenharmony_ci	regmap_write(r, CDA2D_RBMXENDADRS(sub->swm->rb.map),
115162306a36Sopenharmony_ci		     lower_32_bits(end));
115262306a36Sopenharmony_ci	regmap_write(r, CDA2D_RBMXENDADRSU(sub->swm->rb.map),
115362306a36Sopenharmony_ci		     upper_32_bits(end));
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	regmap_write(r, CDA2D_RBADRSLOAD, BIT(sub->swm->rb.map));
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	ret = aiodma_rb_set_threshold(sub, size, 2 * period);
115862306a36Sopenharmony_ci	if (ret)
115962306a36Sopenharmony_ci		return ret;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	if (sub->swm->dir == PORT_DIR_OUTPUT) {
116262306a36Sopenharmony_ci		aiodma_rb_set_rp(sub, start);
116362306a36Sopenharmony_ci		aiodma_rb_set_wp(sub, end - period);
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci		regmap_update_bits(r, CDA2D_RBMXIE(sub->swm->rb.map),
116662306a36Sopenharmony_ci				   CDA2D_RBMXIX_SPACE,
116762306a36Sopenharmony_ci				   CDA2D_RBMXIX_SPACE);
116862306a36Sopenharmony_ci	} else {
116962306a36Sopenharmony_ci		aiodma_rb_set_rp(sub, end - period);
117062306a36Sopenharmony_ci		aiodma_rb_set_wp(sub, start);
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci		regmap_update_bits(r, CDA2D_RBMXIE(sub->swm->rb.map),
117362306a36Sopenharmony_ci				   CDA2D_RBMXIX_REMAIN,
117462306a36Sopenharmony_ci				   CDA2D_RBMXIX_REMAIN);
117562306a36Sopenharmony_ci	}
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	sub->threshold = 2 * period;
117862306a36Sopenharmony_ci	sub->rd_offs = 0;
117962306a36Sopenharmony_ci	sub->wr_offs = 0;
118062306a36Sopenharmony_ci	sub->rd_org = 0;
118162306a36Sopenharmony_ci	sub->wr_org = 0;
118262306a36Sopenharmony_ci	sub->rd_total = 0;
118362306a36Sopenharmony_ci	sub->wr_total = 0;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	return 0;
118662306a36Sopenharmony_ci}
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_civoid aiodma_rb_sync(struct uniphier_aio_sub *sub, u64 start, u64 size,
118962306a36Sopenharmony_ci		    int period)
119062306a36Sopenharmony_ci{
119162306a36Sopenharmony_ci	if (sub->swm->dir == PORT_DIR_OUTPUT) {
119262306a36Sopenharmony_ci		sub->rd_offs = aiodma_rb_get_rp(sub) - start;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci		if (sub->use_mmap) {
119562306a36Sopenharmony_ci			sub->threshold = 2 * period;
119662306a36Sopenharmony_ci			aiodma_rb_set_threshold(sub, size, 2 * period);
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci			sub->wr_offs = sub->rd_offs - period;
119962306a36Sopenharmony_ci			if (sub->rd_offs < period)
120062306a36Sopenharmony_ci				sub->wr_offs += size;
120162306a36Sopenharmony_ci		}
120262306a36Sopenharmony_ci		aiodma_rb_set_wp(sub, sub->wr_offs + start);
120362306a36Sopenharmony_ci	} else {
120462306a36Sopenharmony_ci		sub->wr_offs = aiodma_rb_get_wp(sub) - start;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci		if (sub->use_mmap) {
120762306a36Sopenharmony_ci			sub->threshold = 2 * period;
120862306a36Sopenharmony_ci			aiodma_rb_set_threshold(sub, size, 2 * period);
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci			sub->rd_offs = sub->wr_offs - period;
121162306a36Sopenharmony_ci			if (sub->wr_offs < period)
121262306a36Sopenharmony_ci				sub->rd_offs += size;
121362306a36Sopenharmony_ci		}
121462306a36Sopenharmony_ci		aiodma_rb_set_rp(sub, sub->rd_offs + start);
121562306a36Sopenharmony_ci	}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	sub->rd_total += sub->rd_offs - sub->rd_org;
121862306a36Sopenharmony_ci	if (sub->rd_offs < sub->rd_org)
121962306a36Sopenharmony_ci		sub->rd_total += size;
122062306a36Sopenharmony_ci	sub->wr_total += sub->wr_offs - sub->wr_org;
122162306a36Sopenharmony_ci	if (sub->wr_offs < sub->wr_org)
122262306a36Sopenharmony_ci		sub->wr_total += size;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	sub->rd_org = sub->rd_offs;
122562306a36Sopenharmony_ci	sub->wr_org = sub->wr_offs;
122662306a36Sopenharmony_ci}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_cibool aiodma_rb_is_irq(struct uniphier_aio_sub *sub)
122962306a36Sopenharmony_ci{
123062306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
123162306a36Sopenharmony_ci	u32 ir;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	regmap_read(r, CDA2D_RBMXIR(sub->swm->rb.map), &ir);
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	if (sub->swm->dir == PORT_DIR_OUTPUT)
123662306a36Sopenharmony_ci		return !!(ir & CDA2D_RBMXIX_SPACE);
123762306a36Sopenharmony_ci	else
123862306a36Sopenharmony_ci		return !!(ir & CDA2D_RBMXIX_REMAIN);
123962306a36Sopenharmony_ci}
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_civoid aiodma_rb_clear_irq(struct uniphier_aio_sub *sub)
124262306a36Sopenharmony_ci{
124362306a36Sopenharmony_ci	struct regmap *r = sub->aio->chip->regmap;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	if (sub->swm->dir == PORT_DIR_OUTPUT)
124662306a36Sopenharmony_ci		regmap_write(r, CDA2D_RBMXIR(sub->swm->rb.map),
124762306a36Sopenharmony_ci			     CDA2D_RBMXIX_SPACE);
124862306a36Sopenharmony_ci	else
124962306a36Sopenharmony_ci		regmap_write(r, CDA2D_RBMXIR(sub->swm->rb.map),
125062306a36Sopenharmony_ci			     CDA2D_RBMXIX_REMAIN);
125162306a36Sopenharmony_ci}
1252