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