xref: /kernel/linux/linux-5.10/sound/soc/sh/rcar/cmd.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// Renesas R-Car CMD support
48c2ecf20Sopenharmony_ci//
58c2ecf20Sopenharmony_ci// Copyright (C) 2015 Renesas Solutions Corp.
68c2ecf20Sopenharmony_ci// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "rsnd.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_cistruct rsnd_cmd {
118c2ecf20Sopenharmony_ci	struct rsnd_mod mod;
128c2ecf20Sopenharmony_ci};
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define CMD_NAME "cmd"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define rsnd_cmd_nr(priv) ((priv)->cmd_nr)
178c2ecf20Sopenharmony_ci#define for_each_rsnd_cmd(pos, priv, i)					\
188c2ecf20Sopenharmony_ci	for ((i) = 0;							\
198c2ecf20Sopenharmony_ci	     ((i) < rsnd_cmd_nr(priv)) &&				\
208c2ecf20Sopenharmony_ci		     ((pos) = (struct rsnd_cmd *)(priv)->cmd + i);	\
218c2ecf20Sopenharmony_ci	     i++)
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic int rsnd_cmd_init(struct rsnd_mod *mod,
248c2ecf20Sopenharmony_ci			 struct rsnd_dai_stream *io,
258c2ecf20Sopenharmony_ci			 struct rsnd_priv *priv)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
288c2ecf20Sopenharmony_ci	struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
298c2ecf20Sopenharmony_ci	struct device *dev = rsnd_priv_to_dev(priv);
308c2ecf20Sopenharmony_ci	u32 data;
318c2ecf20Sopenharmony_ci	static const u32 path[] = {
328c2ecf20Sopenharmony_ci		[1] = 1 << 0,
338c2ecf20Sopenharmony_ci		[5] = 1 << 8,
348c2ecf20Sopenharmony_ci		[6] = 1 << 12,
358c2ecf20Sopenharmony_ci		[9] = 1 << 15,
368c2ecf20Sopenharmony_ci	};
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	if (!mix && !dvc)
398c2ecf20Sopenharmony_ci		return 0;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	if (ARRAY_SIZE(path) < rsnd_mod_id(mod) + 1)
428c2ecf20Sopenharmony_ci		return -ENXIO;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	if (mix) {
458c2ecf20Sopenharmony_ci		struct rsnd_dai *rdai;
468c2ecf20Sopenharmony_ci		struct rsnd_mod *src;
478c2ecf20Sopenharmony_ci		struct rsnd_dai_stream *tio;
488c2ecf20Sopenharmony_ci		int i;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci		/*
518c2ecf20Sopenharmony_ci		 * it is assuming that integrater is well understanding about
528c2ecf20Sopenharmony_ci		 * data path. Here doesn't check impossible connection,
538c2ecf20Sopenharmony_ci		 * like src2 + src5
548c2ecf20Sopenharmony_ci		 */
558c2ecf20Sopenharmony_ci		data = 0;
568c2ecf20Sopenharmony_ci		for_each_rsnd_dai(rdai, priv, i) {
578c2ecf20Sopenharmony_ci			tio = &rdai->playback;
588c2ecf20Sopenharmony_ci			src = rsnd_io_to_mod_src(tio);
598c2ecf20Sopenharmony_ci			if (mix == rsnd_io_to_mod_mix(tio))
608c2ecf20Sopenharmony_ci				data |= path[rsnd_mod_id(src)];
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci			tio = &rdai->capture;
638c2ecf20Sopenharmony_ci			src = rsnd_io_to_mod_src(tio);
648c2ecf20Sopenharmony_ci			if (mix == rsnd_io_to_mod_mix(tio))
658c2ecf20Sopenharmony_ci				data |= path[rsnd_mod_id(src)];
668c2ecf20Sopenharmony_ci		}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	} else {
698c2ecf20Sopenharmony_ci		struct rsnd_mod *src = rsnd_io_to_mod_src(io);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci		static const u8 cmd_case[] = {
728c2ecf20Sopenharmony_ci			[0] = 0x3,
738c2ecf20Sopenharmony_ci			[1] = 0x3,
748c2ecf20Sopenharmony_ci			[2] = 0x4,
758c2ecf20Sopenharmony_ci			[3] = 0x1,
768c2ecf20Sopenharmony_ci			[4] = 0x2,
778c2ecf20Sopenharmony_ci			[5] = 0x4,
788c2ecf20Sopenharmony_ci			[6] = 0x1,
798c2ecf20Sopenharmony_ci			[9] = 0x2,
808c2ecf20Sopenharmony_ci		};
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci		if (unlikely(!src))
838c2ecf20Sopenharmony_ci			return -EIO;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci		data = path[rsnd_mod_id(src)] |
868c2ecf20Sopenharmony_ci			cmd_case[rsnd_mod_id(src)] << 16;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	dev_dbg(dev, "ctu/mix path = 0x%08x\n", data);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, CMD_ROUTE_SLCT, data);
928c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, CMD_BUSIF_MODE, rsnd_get_busif_shift(io, mod) | 1);
938c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	rsnd_adg_set_cmd_timsel_gen2(mod, io);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	return 0;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic int rsnd_cmd_start(struct rsnd_mod *mod,
1018c2ecf20Sopenharmony_ci			  struct rsnd_dai_stream *io,
1028c2ecf20Sopenharmony_ci			  struct rsnd_priv *priv)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, CMD_CTRL, 0x10);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	return 0;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic int rsnd_cmd_stop(struct rsnd_mod *mod,
1108c2ecf20Sopenharmony_ci			 struct rsnd_dai_stream *io,
1118c2ecf20Sopenharmony_ci			 struct rsnd_priv *priv)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, CMD_CTRL, 0);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	return 0;
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic struct rsnd_mod_ops rsnd_cmd_ops = {
1198c2ecf20Sopenharmony_ci	.name		= CMD_NAME,
1208c2ecf20Sopenharmony_ci	.init		= rsnd_cmd_init,
1218c2ecf20Sopenharmony_ci	.start		= rsnd_cmd_start,
1228c2ecf20Sopenharmony_ci	.stop		= rsnd_cmd_stop,
1238c2ecf20Sopenharmony_ci	.get_status	= rsnd_mod_get_status,
1248c2ecf20Sopenharmony_ci};
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistatic struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv)))
1298c2ecf20Sopenharmony_ci		id = 0;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id);
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ciint rsnd_cmd_attach(struct rsnd_dai_stream *io, int id)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	struct rsnd_priv *priv = rsnd_io_to_priv(io);
1368c2ecf20Sopenharmony_ci	struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	return rsnd_dai_connect(mod, io, mod->type);
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ciint rsnd_cmd_probe(struct rsnd_priv *priv)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	struct device *dev = rsnd_priv_to_dev(priv);
1448c2ecf20Sopenharmony_ci	struct rsnd_cmd *cmd;
1458c2ecf20Sopenharmony_ci	int i, nr, ret;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	/* This driver doesn't support Gen1 at this point */
1488c2ecf20Sopenharmony_ci	if (rsnd_is_gen1(priv))
1498c2ecf20Sopenharmony_ci		return 0;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	/* same number as DVC */
1528c2ecf20Sopenharmony_ci	nr = priv->dvc_nr;
1538c2ecf20Sopenharmony_ci	if (!nr)
1548c2ecf20Sopenharmony_ci		return 0;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	cmd = devm_kcalloc(dev, nr, sizeof(*cmd), GFP_KERNEL);
1578c2ecf20Sopenharmony_ci	if (!cmd)
1588c2ecf20Sopenharmony_ci		return -ENOMEM;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	priv->cmd_nr	= nr;
1618c2ecf20Sopenharmony_ci	priv->cmd	= cmd;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	for_each_rsnd_cmd(cmd, priv, i) {
1648c2ecf20Sopenharmony_ci		ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
1658c2ecf20Sopenharmony_ci				    &rsnd_cmd_ops, NULL,
1668c2ecf20Sopenharmony_ci				    RSND_MOD_CMD, i);
1678c2ecf20Sopenharmony_ci		if (ret)
1688c2ecf20Sopenharmony_ci			return ret;
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	return 0;
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_civoid rsnd_cmd_remove(struct rsnd_priv *priv)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	struct rsnd_cmd *cmd;
1778c2ecf20Sopenharmony_ci	int i;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	for_each_rsnd_cmd(cmd, priv, i) {
1808c2ecf20Sopenharmony_ci		rsnd_mod_quit(rsnd_mod_get(cmd));
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci}
183