Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e7d850dd authored by Kuninori Morimoto's avatar Kuninori Morimoto Committed by Mark Brown
Browse files

ASoC: rsnd: use mod base common method on SSI-parent



Renesas sound needs many devices
(SSI/SSIU/SRC/CTU/MIX/DVC/CMD/AudioDMAC/AudioDMACpp).
SSI/SRC/CTU/MIX/DVC are implemented as module.
SSI parent, SSIU are implemented as part of SSI
CMD is implemented as part of CTU/MIX/DVC
AudioDMAC/AudioDMACpp are implemented as part of SSI/SRC
It is nice sense that these all devices are implemented as mod.

This patch makes SSI parent mod base common method

Signed-off-by: default avatarKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent c7f69ab5
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -211,6 +211,7 @@ enum rsnd_mod_type {
	RSND_MOD_CMD,
	RSND_MOD_CMD,
	RSND_MOD_SRC,
	RSND_MOD_SRC,
	RSND_MOD_SSIU,
	RSND_MOD_SSIU,
	RSND_MOD_SSIP, /* SSI parent */
	RSND_MOD_SSI,
	RSND_MOD_SSI,
	RSND_MOD_MAX,
	RSND_MOD_MAX,
};
};
@@ -339,6 +340,7 @@ struct rsnd_dai_stream {
};
};
#define rsnd_io_to_mod(io, i)	((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
#define rsnd_io_to_mod(io, i)	((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
#define rsnd_io_to_mod_ssi(io)	rsnd_io_to_mod((io), RSND_MOD_SSI)
#define rsnd_io_to_mod_ssi(io)	rsnd_io_to_mod((io), RSND_MOD_SSI)
#define rsnd_io_to_mod_ssip(io)	rsnd_io_to_mod((io), RSND_MOD_SSIP)
#define rsnd_io_to_mod_src(io)	rsnd_io_to_mod((io), RSND_MOD_SRC)
#define rsnd_io_to_mod_src(io)	rsnd_io_to_mod((io), RSND_MOD_SRC)
#define rsnd_io_to_mod_ctu(io)	rsnd_io_to_mod((io), RSND_MOD_CTU)
#define rsnd_io_to_mod_ctu(io)	rsnd_io_to_mod((io), RSND_MOD_CTU)
#define rsnd_io_to_mod_mix(io)	rsnd_io_to_mod((io), RSND_MOD_MIX)
#define rsnd_io_to_mod_mix(io)	rsnd_io_to_mod((io), RSND_MOD_MIX)
+159 −142
Original line number Original line Diff line number Diff line
@@ -67,7 +67,9 @@ struct rsnd_ssi {


	u32 cr_own;
	u32 cr_own;
	u32 cr_clk;
	u32 cr_clk;
	u32 cr_mode;
	int chan;
	int chan;
	int rate;
	int err;
	int err;
	unsigned int usrcnt;
	unsigned int usrcnt;
};
};
@@ -82,9 +84,9 @@ struct rsnd_ssi {
#define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
#define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
#define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0)
#define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0)
#define rsnd_ssi_parent(ssi) ((ssi)->parent)
#define rsnd_ssi_mode_flags(p) ((p)->info->flags)
#define rsnd_ssi_mode_flags(p) ((p)->info->flags)
#define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id)
#define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id)
#define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io))
#define rsnd_ssi_of_node(priv) \
#define rsnd_ssi_of_node(priv) \
	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi")
	of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi")


@@ -168,7 +170,9 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
	struct rsnd_priv *priv = rsnd_io_to_priv(io);
	struct rsnd_priv *priv = rsnd_io_to_priv(io);
	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
	struct device *dev = rsnd_priv_to_dev(priv);
	struct device *dev = rsnd_priv_to_dev(priv);
	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
	struct rsnd_mod *mod = rsnd_mod_get(ssi);
	struct rsnd_mod *mod = rsnd_mod_get(ssi);
	struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
	int j, ret;
	int j, ret;
	int ssi_clk_mul_table[] = {
	int ssi_clk_mul_table[] = {
		1, 2, 4, 8, 16, 6, 12,
		1, 2, 4, 8, 16, 6, 12,
@@ -176,6 +180,21 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
	unsigned int main_rate;
	unsigned int main_rate;
	unsigned int rate = rsnd_src_get_ssi_rate(priv, io, runtime);
	unsigned int rate = rsnd_src_get_ssi_rate(priv, io, runtime);


	if (!rsnd_rdai_is_clk_master(rdai))
		return 0;

	if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io))
		return 0;

	if (ssi->usrcnt > 1) {
		if (ssi->rate != rate) {
			dev_err(dev, "SSI parent/child should use same rate\n");
			return -EINVAL;
		}

		return 0;
	}

	/*
	/*
	 * Find best clock, and try to start ADG
	 * Find best clock, and try to start ADG
	 */
	 */
@@ -193,6 +212,10 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
			ssi->cr_clk	= FORCE | SWL_32 |
			ssi->cr_clk	= FORCE | SWL_32 |
				SCKD | SWSD | CKDV(j);
				SCKD | SWSD | CKDV(j);


			ssi->rate = rate;

			rsnd_mod_write(mod, SSIWSR, CONT);

			dev_dbg(dev, "%s[%d] outputs %u Hz\n",
			dev_dbg(dev, "%s[%d] outputs %u Hz\n",
				rsnd_mod_name(mod),
				rsnd_mod_name(mod),
				rsnd_mod_id(mod), rate);
				rsnd_mod_id(mod), rate);
@@ -205,113 +228,26 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
	return -EIO;
	return -EIO;
}
}


static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi)
static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi,
{
	struct rsnd_mod *mod = rsnd_mod_get(ssi);

	ssi->cr_clk = 0;
	rsnd_adg_ssi_clk_stop(mod);
}

static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
				     struct rsnd_dai_stream *io)
				     struct rsnd_dai_stream *io)
{
{
	struct rsnd_priv *priv = rsnd_io_to_priv(io);
	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
	struct device *dev = rsnd_priv_to_dev(priv);
	struct rsnd_mod *mod = rsnd_mod_get(ssi);
	struct rsnd_mod *mod = rsnd_mod_get(ssi);
	u32 cr_mode;
	struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
	u32 cr;

	if (0 == ssi->usrcnt) {
		rsnd_mod_power_on(mod);

		if (rsnd_rdai_is_clk_master(rdai)) {
			struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);

			if (ssi_parent)
				rsnd_ssi_hw_start(ssi_parent, io);
			else
				rsnd_ssi_master_clk_start(ssi, io);
		}
	}

	if (rsnd_ssi_is_dma_mode(mod)) {
		cr_mode = UIEN | OIEN |	/* over/under run */
			  DMEN;		/* DMA : enable DMA */
	} else {
		cr_mode = DIEN;		/* PIO : enable Data interrupt */
	}

	cr  =	ssi->cr_own	|
		ssi->cr_clk	|
		cr_mode		|
		EN;

	rsnd_mod_write(mod, SSICR, cr);


	/* enable WS continue */
	if (!rsnd_rdai_is_clk_master(rdai))
	if (rsnd_rdai_is_clk_master(rdai))
		rsnd_mod_write(mod, SSIWSR, CONT);

	/* clear error status */
	rsnd_ssi_status_clear(mod);

	ssi->usrcnt++;

	dev_dbg(dev, "%s[%d] hw started\n",
		rsnd_mod_name(mod), rsnd_mod_id(mod));
}

static void rsnd_ssi_hw_stop(struct rsnd_dai_stream *io, struct rsnd_ssi *ssi)
{
	struct rsnd_mod *mod = rsnd_mod_get(ssi);
	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
	struct device *dev = rsnd_priv_to_dev(priv);
	u32 cr;

	if (0 == ssi->usrcnt) {
		dev_err(dev, "%s called without starting\n", __func__);
		return;
		return;
	}

	ssi->usrcnt--;

	if (0 == ssi->usrcnt) {
		/*
		 * disable all IRQ,
		 * and, wait all data was sent
		 */
		cr  =	ssi->cr_own	|
			ssi->cr_clk;


		rsnd_mod_write(mod, SSICR, cr | EN);
	if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io))
		rsnd_ssi_status_check(mod, DIRQ);
		return;

		/*
		 * disable SSI,
		 * and, wait idle state
		 */
		rsnd_mod_write(mod, SSICR, cr);	/* disabled all */
		rsnd_ssi_status_check(mod, IIRQ);

		if (rsnd_rdai_is_clk_master(rdai)) {
			struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);

			if (ssi_parent)
				rsnd_ssi_hw_stop(io, ssi_parent);
			else
				rsnd_ssi_master_clk_stop(ssi);
		}


		rsnd_mod_power_off(mod);
	if (ssi->usrcnt > 1)
		return;


		ssi->chan = 0;
	ssi->cr_clk	= 0;
	}
	ssi->rate	= 0;


	dev_dbg(dev, "%s[%d] hw stopped\n",
	rsnd_adg_ssi_clk_stop(mod);
		rsnd_mod_name(mod), rsnd_mod_id(mod));
}
}


/*
/*
@@ -325,6 +261,18 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
	u32 cr;
	u32 cr;
	int ret;

	ssi->usrcnt++;

	rsnd_mod_power_on(mod);

	ret = rsnd_ssi_master_clk_start(ssi, io);
	if (ret < 0)
		return ret;

	if (rsnd_ssi_is_parent(mod, io))
		return 0;


	cr = FORCE;
	cr = FORCE;


@@ -359,12 +307,24 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
	if (rsnd_io_is_play(io))
	if (rsnd_io_is_play(io))
		cr |= TRMD;
		cr |= TRMD;


	/*
	 * set ssi parameter
	 */
	ssi->cr_own	= cr;
	ssi->cr_own	= cr;

	if (rsnd_ssi_is_dma_mode(mod)) {
		cr =	UIEN | OIEN |	/* over/under run */
			DMEN;		/* DMA : enable DMA */
	} else {
		cr =	DIEN;		/* PIO : enable Data interrupt */
	}

	ssi->cr_mode	= cr;

	ssi->err	= -1; /* ignore 1st error */
	ssi->err	= -1; /* ignore 1st error */


	/* clear error status */
	rsnd_ssi_status_clear(mod);

	rsnd_ssi_irq_enable(mod);

	return 0;
	return 0;
}
}


@@ -375,6 +335,9 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
	struct device *dev = rsnd_priv_to_dev(priv);
	struct device *dev = rsnd_priv_to_dev(priv);


	if (rsnd_ssi_is_parent(mod, io))
		goto rsnd_ssi_quit_end;

	if (ssi->err > 0)
	if (ssi->err > 0)
		dev_warn(dev, "%s[%d] under/over flow err = %d\n",
		dev_warn(dev, "%s[%d] under/over flow err = %d\n",
			 rsnd_mod_name(mod), rsnd_mod_id(mod), ssi->err);
			 rsnd_mod_name(mod), rsnd_mod_id(mod), ssi->err);
@@ -382,6 +345,19 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
	ssi->cr_own	= 0;
	ssi->cr_own	= 0;
	ssi->err	= 0;
	ssi->err	= 0;


	rsnd_ssi_irq_disable(mod);

rsnd_ssi_quit_end:
	rsnd_ssi_master_clk_stop(ssi, io);

	rsnd_mod_power_off(mod);

	ssi->usrcnt--;

	if (ssi->usrcnt < 0)
		dev_err(dev, "%s[%d] usrcnt error\n",
			rsnd_mod_name(mod), rsnd_mod_id(mod));

	return 0;
	return 0;
}
}


@@ -391,14 +367,13 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
			      struct snd_pcm_hw_params *params)
			      struct snd_pcm_hw_params *params)
{
{
	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
	struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi);
	int chan = params_channels(params);
	int chan = params_channels(params);


	/*
	/*
	 * Already working.
	 * Already working.
	 * It will happen if SSI has parent/child connection.
	 * It will happen if SSI has parent/child connection.
	 */
	 */
	if (ssi->usrcnt) {
	if (ssi->usrcnt > 1) {
		/*
		/*
		 * it is error if child <-> parent SSI uses
		 * it is error if child <-> parent SSI uses
		 * different channels.
		 * different channels.
@@ -407,11 +382,7 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
			return -EIO;
			return -EIO;
	}
	}


	/* It will be removed on rsnd_ssi_hw_stop */
	ssi->chan = chan;
	ssi->chan = chan;
	if (ssi_parent)
		return rsnd_ssi_hw_params(rsnd_mod_get(ssi_parent), io,
					  substream, params);


	return 0;
	return 0;
}
}
@@ -432,32 +403,79 @@ static u32 rsnd_ssi_record_error(struct rsnd_ssi *ssi)
	return status;
	return status;
}
}


static int rsnd_ssi_start(struct rsnd_mod *mod,
static int __rsnd_ssi_start(struct rsnd_mod *mod,
			    struct rsnd_dai_stream *io,
			    struct rsnd_dai_stream *io,
			    struct rsnd_priv *priv)
			    struct rsnd_priv *priv)
{
{
	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
	u32 cr;


	rsnd_ssi_hw_start(ssi, io);
	cr  =	ssi->cr_own	|
		ssi->cr_clk	|
		ssi->cr_mode	|
		EN;


	rsnd_ssi_irq_enable(mod);
	rsnd_mod_write(mod, SSICR, cr);


	return 0;
	return 0;
}
}


static int rsnd_ssi_stop(struct rsnd_mod *mod,
static int rsnd_ssi_start(struct rsnd_mod *mod,
			  struct rsnd_dai_stream *io,
			  struct rsnd_priv *priv)
{
	/*
	 * no limit to start
	 * see also
	 *	rsnd_ssi_stop
	 *	rsnd_ssi_interrupt
	 */
	return __rsnd_ssi_start(mod, io, priv);
}

static int __rsnd_ssi_stop(struct rsnd_mod *mod,
			   struct rsnd_dai_stream *io,
			   struct rsnd_dai_stream *io,
			   struct rsnd_priv *priv)
			   struct rsnd_priv *priv)
{
{
	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
	u32 cr;


	rsnd_ssi_irq_disable(mod);
	/*
	 * disable all IRQ,
	 * and, wait all data was sent
	 */
	cr  =	ssi->cr_own	|
		ssi->cr_clk;

	rsnd_mod_write(mod, SSICR, cr | EN);
	rsnd_ssi_status_check(mod, DIRQ);

	/*
	 * disable SSI,
	 * and, wait idle state
	 */
	rsnd_mod_write(mod, SSICR, cr);	/* disabled all */
	rsnd_ssi_status_check(mod, IIRQ);


	rsnd_ssi_record_error(ssi);
	return 0;
}


	rsnd_ssi_hw_stop(io, ssi);
static int rsnd_ssi_stop(struct rsnd_mod *mod,
			 struct rsnd_dai_stream *io,
			 struct rsnd_priv *priv)
{
	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);


	/*
	 * don't stop if not last user
	 * see also
	 *	rsnd_ssi_start
	 *	rsnd_ssi_interrupt
	 */
	if (ssi->usrcnt > 1)
		return 0;
		return 0;

	return __rsnd_ssi_stop(mod, io, priv);
}
}


static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
@@ -505,8 +523,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
		dev_dbg(dev, "%s[%d] restart\n",
		dev_dbg(dev, "%s[%d] restart\n",
			rsnd_mod_name(mod), rsnd_mod_id(mod));
			rsnd_mod_name(mod), rsnd_mod_id(mod));


		rsnd_ssi_stop(mod, io, priv);
		__rsnd_ssi_stop(mod, io, priv);
		rsnd_ssi_start(mod, io, priv);
		__rsnd_ssi_start(mod, io, priv);
	}
	}


	if (ssi->err > 1024) {
	if (ssi->err > 1024) {
@@ -535,6 +553,27 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
/*
/*
 *		SSI PIO
 *		SSI PIO
 */
 */
static void rsnd_ssi_parent_attach(struct rsnd_mod *mod,
				   struct rsnd_dai_stream *io,
				   struct rsnd_priv *priv)
{
	if (!__rsnd_ssi_is_pin_sharing(mod))
		return;

	switch (rsnd_mod_id(mod)) {
	case 1:
	case 2:
		rsnd_dai_connect(rsnd_ssi_mod_get(priv, 0), io, RSND_MOD_SSIP);
		break;
	case 4:
		rsnd_dai_connect(rsnd_ssi_mod_get(priv, 3), io, RSND_MOD_SSIP);
		break;
	case 8:
		rsnd_dai_connect(rsnd_ssi_mod_get(priv, 7), io, RSND_MOD_SSIP);
		break;
	}
}

static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
				 struct rsnd_dai_stream *io,
				 struct rsnd_dai_stream *io,
				 struct rsnd_priv *priv)
				 struct rsnd_priv *priv)
@@ -543,6 +582,8 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod,
	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
	int ret;
	int ret;


	rsnd_ssi_parent_attach(mod, io, priv);

	ret = rsnd_ssiu_attach(io, mod);
	ret = rsnd_ssiu_attach(io, mod);
	if (ret < 0)
	if (ret < 0)
		return ret;
		return ret;
@@ -679,28 +720,6 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
	return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE);
	return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE);
}
}


static void rsnd_ssi_parent_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi)
{
	struct rsnd_mod *mod = rsnd_mod_get(ssi);

	if (!__rsnd_ssi_is_pin_sharing(mod))
		return;

	switch (rsnd_mod_id(mod)) {
	case 1:
	case 2:
		ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 0));
		break;
	case 4:
		ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 3));
		break;
	case 8:
		ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 7));
		break;
	}
}


static void rsnd_of_parse_ssi(struct platform_device *pdev,
static void rsnd_of_parse_ssi(struct platform_device *pdev,
			      const struct rsnd_of_data *of_data,
			      const struct rsnd_of_data *of_data,
			      struct rsnd_priv *priv)
			      struct rsnd_priv *priv)
@@ -810,8 +829,6 @@ int rsnd_ssi_probe(struct platform_device *pdev,
				    RSND_MOD_SSI, i);
				    RSND_MOD_SSI, i);
		if (ret)
		if (ret)
			return ret;
			return ret;

		rsnd_ssi_parent_setup(priv, ssi);
	}
	}


	return 0;
	return 0;