Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Renesas R-Car CMD support
0004 //
0005 // Copyright (C) 2015 Renesas Solutions Corp.
0006 // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
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          * it is assuming that integrater is well understanding about
0050          * data path. Here doesn't check impossible connection,
0051          * like src2 + src5
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     /* This driver doesn't support Gen1 at this point */
0161     if (rsnd_is_gen1(priv))
0162         return 0;
0163 
0164     /* same number as DVC */
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 }