1*c087a94bSLad Prabhakar // SPDX-License-Identifier: GPL-2.0 2*c087a94bSLad Prabhakar // 3*c087a94bSLad Prabhakar // Renesas R-Car CMD support 4*c087a94bSLad Prabhakar // 5*c087a94bSLad Prabhakar // Copyright (C) 2015 Renesas Solutions Corp. 6*c087a94bSLad Prabhakar // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 7*c087a94bSLad Prabhakar 8*c087a94bSLad Prabhakar #include "rsnd.h" 9*c087a94bSLad Prabhakar 10*c087a94bSLad Prabhakar struct rsnd_cmd { 11*c087a94bSLad Prabhakar struct rsnd_mod mod; 12*c087a94bSLad Prabhakar }; 13*c087a94bSLad Prabhakar 14*c087a94bSLad Prabhakar #define CMD_NAME "cmd" 15*c087a94bSLad Prabhakar 16*c087a94bSLad Prabhakar #define rsnd_cmd_nr(priv) ((priv)->cmd_nr) 17*c087a94bSLad Prabhakar #define for_each_rsnd_cmd(pos, priv, i) \ 18*c087a94bSLad Prabhakar for ((i) = 0; \ 19*c087a94bSLad Prabhakar ((i) < rsnd_cmd_nr(priv)) && \ 20*c087a94bSLad Prabhakar ((pos) = (struct rsnd_cmd *)(priv)->cmd + i); \ 21*c087a94bSLad Prabhakar i++) 22*c087a94bSLad Prabhakar 23*c087a94bSLad Prabhakar static int rsnd_cmd_init(struct rsnd_mod *mod, 24*c087a94bSLad Prabhakar struct rsnd_dai_stream *io, 25*c087a94bSLad Prabhakar struct rsnd_priv *priv) 26*c087a94bSLad Prabhakar { 27*c087a94bSLad Prabhakar struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); 28*c087a94bSLad Prabhakar struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); 29*c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv); 30*c087a94bSLad Prabhakar u32 data; 31*c087a94bSLad Prabhakar static const u32 path[] = { 32*c087a94bSLad Prabhakar [1] = 1 << 0, 33*c087a94bSLad Prabhakar [5] = 1 << 8, 34*c087a94bSLad Prabhakar [6] = 1 << 12, 35*c087a94bSLad Prabhakar [9] = 1 << 15, 36*c087a94bSLad Prabhakar }; 37*c087a94bSLad Prabhakar 38*c087a94bSLad Prabhakar if (!mix && !dvc) 39*c087a94bSLad Prabhakar return 0; 40*c087a94bSLad Prabhakar 41*c087a94bSLad Prabhakar if (ARRAY_SIZE(path) < rsnd_mod_id(mod) + 1) 42*c087a94bSLad Prabhakar return -ENXIO; 43*c087a94bSLad Prabhakar 44*c087a94bSLad Prabhakar if (mix) { 45*c087a94bSLad Prabhakar struct rsnd_dai *rdai; 46*c087a94bSLad Prabhakar int i; 47*c087a94bSLad Prabhakar 48*c087a94bSLad Prabhakar /* 49*c087a94bSLad Prabhakar * it is assuming that integrater is well understanding about 50*c087a94bSLad Prabhakar * data path. Here doesn't check impossible connection, 51*c087a94bSLad Prabhakar * like src2 + src5 52*c087a94bSLad Prabhakar */ 53*c087a94bSLad Prabhakar data = 0; 54*c087a94bSLad Prabhakar for_each_rsnd_dai(rdai, priv, i) { 55*c087a94bSLad Prabhakar struct rsnd_dai_stream *tio = &rdai->playback; 56*c087a94bSLad Prabhakar struct rsnd_mod *src = rsnd_io_to_mod_src(tio); 57*c087a94bSLad Prabhakar 58*c087a94bSLad Prabhakar if (mix == rsnd_io_to_mod_mix(tio)) 59*c087a94bSLad Prabhakar data |= path[rsnd_mod_id(src)]; 60*c087a94bSLad Prabhakar 61*c087a94bSLad Prabhakar tio = &rdai->capture; 62*c087a94bSLad Prabhakar src = rsnd_io_to_mod_src(tio); 63*c087a94bSLad Prabhakar if (mix == rsnd_io_to_mod_mix(tio)) 64*c087a94bSLad Prabhakar data |= path[rsnd_mod_id(src)]; 65*c087a94bSLad Prabhakar } 66*c087a94bSLad Prabhakar 67*c087a94bSLad Prabhakar } else { 68*c087a94bSLad Prabhakar struct rsnd_mod *src = rsnd_io_to_mod_src(io); 69*c087a94bSLad Prabhakar 70*c087a94bSLad Prabhakar static const u8 cmd_case[] = { 71*c087a94bSLad Prabhakar [0] = 0x3, 72*c087a94bSLad Prabhakar [1] = 0x3, 73*c087a94bSLad Prabhakar [2] = 0x4, 74*c087a94bSLad Prabhakar [3] = 0x1, 75*c087a94bSLad Prabhakar [4] = 0x2, 76*c087a94bSLad Prabhakar [5] = 0x4, 77*c087a94bSLad Prabhakar [6] = 0x1, 78*c087a94bSLad Prabhakar [9] = 0x2, 79*c087a94bSLad Prabhakar }; 80*c087a94bSLad Prabhakar 81*c087a94bSLad Prabhakar if (unlikely(!src)) 82*c087a94bSLad Prabhakar return -EIO; 83*c087a94bSLad Prabhakar 84*c087a94bSLad Prabhakar data = path[rsnd_mod_id(src)] | 85*c087a94bSLad Prabhakar cmd_case[rsnd_mod_id(src)] << 16; 86*c087a94bSLad Prabhakar } 87*c087a94bSLad Prabhakar 88*c087a94bSLad Prabhakar dev_dbg(dev, "ctu/mix path = 0x%08x\n", data); 89*c087a94bSLad Prabhakar 90*c087a94bSLad Prabhakar rsnd_mod_write(mod, CMD_ROUTE_SLCT, data); 91*c087a94bSLad Prabhakar rsnd_mod_write(mod, CMD_BUSIF_MODE, rsnd_get_busif_shift(io, mod) | 1); 92*c087a94bSLad Prabhakar rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); 93*c087a94bSLad Prabhakar 94*c087a94bSLad Prabhakar rsnd_adg_set_cmd_timsel_gen2(mod, io); 95*c087a94bSLad Prabhakar 96*c087a94bSLad Prabhakar return 0; 97*c087a94bSLad Prabhakar } 98*c087a94bSLad Prabhakar 99*c087a94bSLad Prabhakar static int rsnd_cmd_start(struct rsnd_mod *mod, 100*c087a94bSLad Prabhakar struct rsnd_dai_stream *io, 101*c087a94bSLad Prabhakar struct rsnd_priv *priv) 102*c087a94bSLad Prabhakar { 103*c087a94bSLad Prabhakar rsnd_mod_write(mod, CMD_CTRL, 0x10); 104*c087a94bSLad Prabhakar 105*c087a94bSLad Prabhakar return 0; 106*c087a94bSLad Prabhakar } 107*c087a94bSLad Prabhakar 108*c087a94bSLad Prabhakar static int rsnd_cmd_stop(struct rsnd_mod *mod, 109*c087a94bSLad Prabhakar struct rsnd_dai_stream *io, 110*c087a94bSLad Prabhakar struct rsnd_priv *priv) 111*c087a94bSLad Prabhakar { 112*c087a94bSLad Prabhakar rsnd_mod_write(mod, CMD_CTRL, 0); 113*c087a94bSLad Prabhakar 114*c087a94bSLad Prabhakar return 0; 115*c087a94bSLad Prabhakar } 116*c087a94bSLad Prabhakar 117*c087a94bSLad Prabhakar #ifdef CONFIG_DEBUG_FS 118*c087a94bSLad Prabhakar static void rsnd_cmd_debug_info(struct seq_file *m, 119*c087a94bSLad Prabhakar struct rsnd_dai_stream *io, 120*c087a94bSLad Prabhakar struct rsnd_mod *mod) 121*c087a94bSLad Prabhakar { 122*c087a94bSLad Prabhakar rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU, 123*c087a94bSLad Prabhakar 0x180 + rsnd_mod_id_raw(mod) * 0x20, 0x30); 124*c087a94bSLad Prabhakar } 125*c087a94bSLad Prabhakar #define DEBUG_INFO .debug_info = rsnd_cmd_debug_info 126*c087a94bSLad Prabhakar #else 127*c087a94bSLad Prabhakar #define DEBUG_INFO 128*c087a94bSLad Prabhakar #endif 129*c087a94bSLad Prabhakar 130*c087a94bSLad Prabhakar static struct rsnd_mod_ops rsnd_cmd_ops = { 131*c087a94bSLad Prabhakar .name = CMD_NAME, 132*c087a94bSLad Prabhakar .init = rsnd_cmd_init, 133*c087a94bSLad Prabhakar .start = rsnd_cmd_start, 134*c087a94bSLad Prabhakar .stop = rsnd_cmd_stop, 135*c087a94bSLad Prabhakar .get_status = rsnd_mod_get_status, 136*c087a94bSLad Prabhakar DEBUG_INFO 137*c087a94bSLad Prabhakar }; 138*c087a94bSLad Prabhakar 139*c087a94bSLad Prabhakar static struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id) 140*c087a94bSLad Prabhakar { 141*c087a94bSLad Prabhakar if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv))) 142*c087a94bSLad Prabhakar id = 0; 143*c087a94bSLad Prabhakar 144*c087a94bSLad Prabhakar return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id); 145*c087a94bSLad Prabhakar } 146*c087a94bSLad Prabhakar int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id) 147*c087a94bSLad Prabhakar { 148*c087a94bSLad Prabhakar struct rsnd_priv *priv = rsnd_io_to_priv(io); 149*c087a94bSLad Prabhakar struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id); 150*c087a94bSLad Prabhakar 151*c087a94bSLad Prabhakar return rsnd_dai_connect(mod, io, mod->type); 152*c087a94bSLad Prabhakar } 153*c087a94bSLad Prabhakar 154*c087a94bSLad Prabhakar int rsnd_cmd_probe(struct rsnd_priv *priv) 155*c087a94bSLad Prabhakar { 156*c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv); 157*c087a94bSLad Prabhakar struct rsnd_cmd *cmd; 158*c087a94bSLad Prabhakar int i, nr; 159*c087a94bSLad Prabhakar 160*c087a94bSLad Prabhakar /* same number as DVC */ 161*c087a94bSLad Prabhakar nr = priv->dvc_nr; 162*c087a94bSLad Prabhakar if (!nr) 163*c087a94bSLad Prabhakar return 0; 164*c087a94bSLad Prabhakar 165*c087a94bSLad Prabhakar cmd = devm_kcalloc(dev, nr, sizeof(*cmd), GFP_KERNEL); 166*c087a94bSLad Prabhakar if (!cmd) 167*c087a94bSLad Prabhakar return -ENOMEM; 168*c087a94bSLad Prabhakar 169*c087a94bSLad Prabhakar priv->cmd_nr = nr; 170*c087a94bSLad Prabhakar priv->cmd = cmd; 171*c087a94bSLad Prabhakar 172*c087a94bSLad Prabhakar for_each_rsnd_cmd(cmd, priv, i) { 173*c087a94bSLad Prabhakar int ret = rsnd_mod_init(priv, rsnd_mod_get(cmd), 174*c087a94bSLad Prabhakar &rsnd_cmd_ops, NULL, 175*c087a94bSLad Prabhakar RSND_MOD_CMD, i); 176*c087a94bSLad Prabhakar if (ret) 177*c087a94bSLad Prabhakar return ret; 178*c087a94bSLad Prabhakar } 179*c087a94bSLad Prabhakar 180*c087a94bSLad Prabhakar return 0; 181*c087a94bSLad Prabhakar } 182*c087a94bSLad Prabhakar 183*c087a94bSLad Prabhakar void rsnd_cmd_remove(struct rsnd_priv *priv) 184*c087a94bSLad Prabhakar { 185*c087a94bSLad Prabhakar struct rsnd_cmd *cmd; 186*c087a94bSLad Prabhakar int i; 187*c087a94bSLad Prabhakar 188*c087a94bSLad Prabhakar for_each_rsnd_cmd(cmd, priv, i) { 189*c087a94bSLad Prabhakar rsnd_mod_quit(rsnd_mod_get(cmd)); 190*c087a94bSLad Prabhakar } 191*c087a94bSLad Prabhakar } 192