0001
0002
0003
0004
0005
0006
0007
0008 #include "rsnd.h"
0009
0010 struct rsnd_cmd {
0011 struct rsnd_mod mod;
0012 };
0013
0014 #define CMD_NAME "cmd"
0015
0016 #define rsnd_cmd_nr(priv) ((priv)->cmd_nr)
0017 #define for_each_rsnd_cmd(pos, priv, i) \
0018 for ((i) = 0; \
0019 ((i) < rsnd_cmd_nr(priv)) && \
0020 ((pos) = (struct rsnd_cmd *)(priv)->cmd + i); \
0021 i++)
0022
0023 static int rsnd_cmd_init(struct rsnd_mod *mod,
0024 struct rsnd_dai_stream *io,
0025 struct rsnd_priv *priv)
0026 {
0027 struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
0028 struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
0029 struct device *dev = rsnd_priv_to_dev(priv);
0030 u32 data;
0031 static const u32 path[] = {
0032 [1] = 1 << 0,
0033 [5] = 1 << 8,
0034 [6] = 1 << 12,
0035 [9] = 1 << 15,
0036 };
0037
0038 if (!mix && !dvc)
0039 return 0;
0040
0041 if (ARRAY_SIZE(path) < rsnd_mod_id(mod) + 1)
0042 return -ENXIO;
0043
0044 if (mix) {
0045 struct rsnd_dai *rdai;
0046 int i;
0047
0048
0049
0050
0051
0052
0053 data = 0;
0054 for_each_rsnd_dai(rdai, priv, i) {
0055 struct rsnd_dai_stream *tio = &rdai->playback;
0056 struct rsnd_mod *src = rsnd_io_to_mod_src(tio);
0057
0058 if (mix == rsnd_io_to_mod_mix(tio))
0059 data |= path[rsnd_mod_id(src)];
0060
0061 tio = &rdai->capture;
0062 src = rsnd_io_to_mod_src(tio);
0063 if (mix == rsnd_io_to_mod_mix(tio))
0064 data |= path[rsnd_mod_id(src)];
0065 }
0066
0067 } else {
0068 struct rsnd_mod *src = rsnd_io_to_mod_src(io);
0069
0070 static const u8 cmd_case[] = {
0071 [0] = 0x3,
0072 [1] = 0x3,
0073 [2] = 0x4,
0074 [3] = 0x1,
0075 [4] = 0x2,
0076 [5] = 0x4,
0077 [6] = 0x1,
0078 [9] = 0x2,
0079 };
0080
0081 if (unlikely(!src))
0082 return -EIO;
0083
0084 data = path[rsnd_mod_id(src)] |
0085 cmd_case[rsnd_mod_id(src)] << 16;
0086 }
0087
0088 dev_dbg(dev, "ctu/mix path = 0x%08x\n", data);
0089
0090 rsnd_mod_write(mod, CMD_ROUTE_SLCT, data);
0091 rsnd_mod_write(mod, CMD_BUSIF_MODE, rsnd_get_busif_shift(io, mod) | 1);
0092 rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
0093
0094 rsnd_adg_set_cmd_timsel_gen2(mod, io);
0095
0096 return 0;
0097 }
0098
0099 static int rsnd_cmd_start(struct rsnd_mod *mod,
0100 struct rsnd_dai_stream *io,
0101 struct rsnd_priv *priv)
0102 {
0103 rsnd_mod_write(mod, CMD_CTRL, 0x10);
0104
0105 return 0;
0106 }
0107
0108 static int rsnd_cmd_stop(struct rsnd_mod *mod,
0109 struct rsnd_dai_stream *io,
0110 struct rsnd_priv *priv)
0111 {
0112 rsnd_mod_write(mod, CMD_CTRL, 0);
0113
0114 return 0;
0115 }
0116
0117 #ifdef CONFIG_DEBUG_FS
0118 static void rsnd_cmd_debug_info(struct seq_file *m,
0119 struct rsnd_dai_stream *io,
0120 struct rsnd_mod *mod)
0121 {
0122 rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU,
0123 0x180 + rsnd_mod_id_raw(mod) * 0x20, 0x30);
0124 }
0125 #define DEBUG_INFO .debug_info = rsnd_cmd_debug_info
0126 #else
0127 #define DEBUG_INFO
0128 #endif
0129
0130 static struct rsnd_mod_ops rsnd_cmd_ops = {
0131 .name = CMD_NAME,
0132 .init = rsnd_cmd_init,
0133 .start = rsnd_cmd_start,
0134 .stop = rsnd_cmd_stop,
0135 .get_status = rsnd_mod_get_status,
0136 DEBUG_INFO
0137 };
0138
0139 static struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id)
0140 {
0141 if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv)))
0142 id = 0;
0143
0144 return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id);
0145 }
0146 int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id)
0147 {
0148 struct rsnd_priv *priv = rsnd_io_to_priv(io);
0149 struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id);
0150
0151 return rsnd_dai_connect(mod, io, mod->type);
0152 }
0153
0154 int rsnd_cmd_probe(struct rsnd_priv *priv)
0155 {
0156 struct device *dev = rsnd_priv_to_dev(priv);
0157 struct rsnd_cmd *cmd;
0158 int i, nr;
0159
0160
0161 if (rsnd_is_gen1(priv))
0162 return 0;
0163
0164
0165 nr = priv->dvc_nr;
0166 if (!nr)
0167 return 0;
0168
0169 cmd = devm_kcalloc(dev, nr, sizeof(*cmd), GFP_KERNEL);
0170 if (!cmd)
0171 return -ENOMEM;
0172
0173 priv->cmd_nr = nr;
0174 priv->cmd = cmd;
0175
0176 for_each_rsnd_cmd(cmd, priv, i) {
0177 int ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
0178 &rsnd_cmd_ops, NULL,
0179 RSND_MOD_CMD, i);
0180 if (ret)
0181 return ret;
0182 }
0183
0184 return 0;
0185 }
0186
0187 void rsnd_cmd_remove(struct rsnd_priv *priv)
0188 {
0189 struct rsnd_cmd *cmd;
0190 int i;
0191
0192 for_each_rsnd_cmd(cmd, priv, i) {
0193 rsnd_mod_quit(rsnd_mod_get(cmd));
0194 }
0195 }