162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Renesas R-Car CMD support 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (C) 2015 Renesas Solutions Corp. 662306a36Sopenharmony_ci// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "rsnd.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_cistruct rsnd_cmd { 1162306a36Sopenharmony_ci struct rsnd_mod mod; 1262306a36Sopenharmony_ci}; 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define CMD_NAME "cmd" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define rsnd_cmd_nr(priv) ((priv)->cmd_nr) 1762306a36Sopenharmony_ci#define for_each_rsnd_cmd(pos, priv, i) \ 1862306a36Sopenharmony_ci for ((i) = 0; \ 1962306a36Sopenharmony_ci ((i) < rsnd_cmd_nr(priv)) && \ 2062306a36Sopenharmony_ci ((pos) = (struct rsnd_cmd *)(priv)->cmd + i); \ 2162306a36Sopenharmony_ci i++) 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic int rsnd_cmd_init(struct rsnd_mod *mod, 2462306a36Sopenharmony_ci struct rsnd_dai_stream *io, 2562306a36Sopenharmony_ci struct rsnd_priv *priv) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); 2862306a36Sopenharmony_ci struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); 2962306a36Sopenharmony_ci struct device *dev = rsnd_priv_to_dev(priv); 3062306a36Sopenharmony_ci u32 data; 3162306a36Sopenharmony_ci static const u32 path[] = { 3262306a36Sopenharmony_ci [1] = 1 << 0, 3362306a36Sopenharmony_ci [5] = 1 << 8, 3462306a36Sopenharmony_ci [6] = 1 << 12, 3562306a36Sopenharmony_ci [9] = 1 << 15, 3662306a36Sopenharmony_ci }; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (!mix && !dvc) 3962306a36Sopenharmony_ci return 0; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (ARRAY_SIZE(path) < rsnd_mod_id(mod) + 1) 4262306a36Sopenharmony_ci return -ENXIO; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (mix) { 4562306a36Sopenharmony_ci struct rsnd_dai *rdai; 4662306a36Sopenharmony_ci int i; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* 4962306a36Sopenharmony_ci * it is assuming that integrater is well understanding about 5062306a36Sopenharmony_ci * data path. Here doesn't check impossible connection, 5162306a36Sopenharmony_ci * like src2 + src5 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ci data = 0; 5462306a36Sopenharmony_ci for_each_rsnd_dai(rdai, priv, i) { 5562306a36Sopenharmony_ci struct rsnd_dai_stream *tio = &rdai->playback; 5662306a36Sopenharmony_ci struct rsnd_mod *src = rsnd_io_to_mod_src(tio); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (mix == rsnd_io_to_mod_mix(tio)) 5962306a36Sopenharmony_ci data |= path[rsnd_mod_id(src)]; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci tio = &rdai->capture; 6262306a36Sopenharmony_ci src = rsnd_io_to_mod_src(tio); 6362306a36Sopenharmony_ci if (mix == rsnd_io_to_mod_mix(tio)) 6462306a36Sopenharmony_ci data |= path[rsnd_mod_id(src)]; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci } else { 6862306a36Sopenharmony_ci struct rsnd_mod *src = rsnd_io_to_mod_src(io); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci static const u8 cmd_case[] = { 7162306a36Sopenharmony_ci [0] = 0x3, 7262306a36Sopenharmony_ci [1] = 0x3, 7362306a36Sopenharmony_ci [2] = 0x4, 7462306a36Sopenharmony_ci [3] = 0x1, 7562306a36Sopenharmony_ci [4] = 0x2, 7662306a36Sopenharmony_ci [5] = 0x4, 7762306a36Sopenharmony_ci [6] = 0x1, 7862306a36Sopenharmony_ci [9] = 0x2, 7962306a36Sopenharmony_ci }; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (unlikely(!src)) 8262306a36Sopenharmony_ci return -EIO; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci data = path[rsnd_mod_id(src)] | 8562306a36Sopenharmony_ci cmd_case[rsnd_mod_id(src)] << 16; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci dev_dbg(dev, "ctu/mix path = 0x%08x\n", data); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci rsnd_mod_write(mod, CMD_ROUTE_SLCT, data); 9162306a36Sopenharmony_ci rsnd_mod_write(mod, CMD_BUSIF_MODE, rsnd_get_busif_shift(io, mod) | 1); 9262306a36Sopenharmony_ci rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci rsnd_adg_set_cmd_timsel_gen2(mod, io); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci return 0; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic int rsnd_cmd_start(struct rsnd_mod *mod, 10062306a36Sopenharmony_ci struct rsnd_dai_stream *io, 10162306a36Sopenharmony_ci struct rsnd_priv *priv) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci rsnd_mod_write(mod, CMD_CTRL, 0x10); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci return 0; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int rsnd_cmd_stop(struct rsnd_mod *mod, 10962306a36Sopenharmony_ci struct rsnd_dai_stream *io, 11062306a36Sopenharmony_ci struct rsnd_priv *priv) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci rsnd_mod_write(mod, CMD_CTRL, 0); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return 0; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 11862306a36Sopenharmony_cistatic void rsnd_cmd_debug_info(struct seq_file *m, 11962306a36Sopenharmony_ci struct rsnd_dai_stream *io, 12062306a36Sopenharmony_ci struct rsnd_mod *mod) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, 12362306a36Sopenharmony_ci 0x180 + rsnd_mod_id_raw(mod) * 0x20, 0x30); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci#define DEBUG_INFO .debug_info = rsnd_cmd_debug_info 12662306a36Sopenharmony_ci#else 12762306a36Sopenharmony_ci#define DEBUG_INFO 12862306a36Sopenharmony_ci#endif 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic struct rsnd_mod_ops rsnd_cmd_ops = { 13162306a36Sopenharmony_ci .name = CMD_NAME, 13262306a36Sopenharmony_ci .init = rsnd_cmd_init, 13362306a36Sopenharmony_ci .start = rsnd_cmd_start, 13462306a36Sopenharmony_ci .stop = rsnd_cmd_stop, 13562306a36Sopenharmony_ci .get_status = rsnd_mod_get_status, 13662306a36Sopenharmony_ci DEBUG_INFO 13762306a36Sopenharmony_ci}; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv))) 14262306a36Sopenharmony_ci id = 0; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ciint rsnd_cmd_attach(struct rsnd_dai_stream *io, int id) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct rsnd_priv *priv = rsnd_io_to_priv(io); 14962306a36Sopenharmony_ci struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return rsnd_dai_connect(mod, io, mod->type); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ciint rsnd_cmd_probe(struct rsnd_priv *priv) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct device *dev = rsnd_priv_to_dev(priv); 15762306a36Sopenharmony_ci struct rsnd_cmd *cmd; 15862306a36Sopenharmony_ci int i, nr; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* This driver doesn't support Gen1 at this point */ 16162306a36Sopenharmony_ci if (rsnd_is_gen1(priv)) 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* same number as DVC */ 16562306a36Sopenharmony_ci nr = priv->dvc_nr; 16662306a36Sopenharmony_ci if (!nr) 16762306a36Sopenharmony_ci return 0; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci cmd = devm_kcalloc(dev, nr, sizeof(*cmd), GFP_KERNEL); 17062306a36Sopenharmony_ci if (!cmd) 17162306a36Sopenharmony_ci return -ENOMEM; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci priv->cmd_nr = nr; 17462306a36Sopenharmony_ci priv->cmd = cmd; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci for_each_rsnd_cmd(cmd, priv, i) { 17762306a36Sopenharmony_ci int ret = rsnd_mod_init(priv, rsnd_mod_get(cmd), 17862306a36Sopenharmony_ci &rsnd_cmd_ops, NULL, 17962306a36Sopenharmony_ci RSND_MOD_CMD, i); 18062306a36Sopenharmony_ci if (ret) 18162306a36Sopenharmony_ci return ret; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci return 0; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_civoid rsnd_cmd_remove(struct rsnd_priv *priv) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci struct rsnd_cmd *cmd; 19062306a36Sopenharmony_ci int i; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci for_each_rsnd_cmd(cmd, priv, i) { 19362306a36Sopenharmony_ci rsnd_mod_quit(rsnd_mod_get(cmd)); 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci} 196