ctu.c 5.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * ctu.c
 *
 * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include "rsnd.h"

#define CTU_NAME_SIZE	16
#define CTU_NAME "ctu"

struct rsnd_ctu {
	struct rsnd_mod mod;
17
	int channels;
18 19 20 21 22 23 24 25 26
};

#define rsnd_ctu_nr(priv) ((priv)->ctu_nr)
#define for_each_rsnd_ctu(pos, priv, i)					\
	for ((i) = 0;							\
	     ((i) < rsnd_ctu_nr(priv)) &&				\
		     ((pos) = (struct rsnd_ctu *)(priv)->ctu + i);	\
	     i++)

27 28 29
#define rsnd_mod_to_ctu(_mod)	\
	container_of((_mod), struct rsnd_ctu, mod)

30
#define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id)
31 32 33 34 35 36 37

static void rsnd_ctu_activation(struct rsnd_mod *mod)
{
	rsnd_mod_write(mod, CTU_SWRSR, 0);
	rsnd_mod_write(mod, CTU_SWRSR, 1);
}

38 39 40 41 42 43
static void rsnd_ctu_halt(struct rsnd_mod *mod)
{
	rsnd_mod_write(mod, CTU_CTUIR, 1);
	rsnd_mod_write(mod, CTU_SWRSR, 0);
}

44 45 46 47 48 49 50
int rsnd_ctu_converted_channel(struct rsnd_mod *mod)
{
	struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);

	return ctu->channels;
}

51 52 53 54 55 56 57
static int rsnd_ctu_probe_(struct rsnd_mod *mod,
			   struct rsnd_dai_stream *io,
			   struct rsnd_priv *priv)
{
	return rsnd_cmd_attach(io, rsnd_mod_id(mod) / 4);
}

58 59 60 61 62
static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
			       struct rsnd_mod *mod)
{
	rsnd_mod_write(mod, CTU_CTUIR, 1);

63
	rsnd_mod_write(mod, CTU_ADINR, rsnd_runtime_channel_original(io));
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105

	rsnd_mod_write(mod, CTU_CPMDR, 0);
	rsnd_mod_write(mod, CTU_SCMDR, 0);
	rsnd_mod_write(mod, CTU_SV00R, 0);
	rsnd_mod_write(mod, CTU_SV01R, 0);
	rsnd_mod_write(mod, CTU_SV02R, 0);
	rsnd_mod_write(mod, CTU_SV03R, 0);
	rsnd_mod_write(mod, CTU_SV04R, 0);
	rsnd_mod_write(mod, CTU_SV05R, 0);
	rsnd_mod_write(mod, CTU_SV06R, 0);
	rsnd_mod_write(mod, CTU_SV07R, 0);

	rsnd_mod_write(mod, CTU_SV10R, 0);
	rsnd_mod_write(mod, CTU_SV11R, 0);
	rsnd_mod_write(mod, CTU_SV12R, 0);
	rsnd_mod_write(mod, CTU_SV13R, 0);
	rsnd_mod_write(mod, CTU_SV14R, 0);
	rsnd_mod_write(mod, CTU_SV15R, 0);
	rsnd_mod_write(mod, CTU_SV16R, 0);
	rsnd_mod_write(mod, CTU_SV17R, 0);

	rsnd_mod_write(mod, CTU_SV20R, 0);
	rsnd_mod_write(mod, CTU_SV21R, 0);
	rsnd_mod_write(mod, CTU_SV22R, 0);
	rsnd_mod_write(mod, CTU_SV23R, 0);
	rsnd_mod_write(mod, CTU_SV24R, 0);
	rsnd_mod_write(mod, CTU_SV25R, 0);
	rsnd_mod_write(mod, CTU_SV26R, 0);
	rsnd_mod_write(mod, CTU_SV27R, 0);

	rsnd_mod_write(mod, CTU_SV30R, 0);
	rsnd_mod_write(mod, CTU_SV31R, 0);
	rsnd_mod_write(mod, CTU_SV32R, 0);
	rsnd_mod_write(mod, CTU_SV33R, 0);
	rsnd_mod_write(mod, CTU_SV34R, 0);
	rsnd_mod_write(mod, CTU_SV35R, 0);
	rsnd_mod_write(mod, CTU_SV36R, 0);
	rsnd_mod_write(mod, CTU_SV37R, 0);

	rsnd_mod_write(mod, CTU_CTUIR, 0);
}

106 107 108 109
static int rsnd_ctu_init(struct rsnd_mod *mod,
			 struct rsnd_dai_stream *io,
			 struct rsnd_priv *priv)
{
110
	rsnd_mod_power_on(mod);
111

112 113
	rsnd_ctu_activation(mod);

114
	rsnd_ctu_value_init(io, mod);
115 116 117 118 119 120 121 122

	return 0;
}

static int rsnd_ctu_quit(struct rsnd_mod *mod,
			 struct rsnd_dai_stream *io,
			 struct rsnd_priv *priv)
{
123 124
	rsnd_ctu_halt(mod);

125
	rsnd_mod_power_off(mod);
126 127 128 129

	return 0;
}

130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
static int rsnd_ctu_hw_params(struct rsnd_mod *mod,
			      struct rsnd_dai_stream *io,
			      struct snd_pcm_substream *substream,
			      struct snd_pcm_hw_params *fe_params)
{
	struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
	struct snd_soc_pcm_runtime *fe = substream->private_data;

	/*
	 * CTU assumes that it is used under DPCM if user want to use
	 * channel transfer. Then, CTU should be FE.
	 * And then, this function will be called *after* BE settings.
	 * this means, each BE already has fixuped hw_params.
	 * see
	 *	dpcm_fe_dai_hw_params()
	 *	dpcm_be_dai_hw_params()
	 */
	ctu->channels = 0;
	if (fe->dai_link->dynamic) {
		struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
		struct device *dev = rsnd_priv_to_dev(priv);
		struct snd_soc_dpcm *dpcm;
		struct snd_pcm_hw_params *be_params;
		int stream = substream->stream;

		list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
			be_params = &dpcm->hw_params;
			if (params_channels(fe_params) != params_channels(be_params))
				ctu->channels = params_channels(be_params);
		}

		dev_dbg(dev, "CTU convert channels %d\n", ctu->channels);
	}

	return 0;
}

167 168
static struct rsnd_mod_ops rsnd_ctu_ops = {
	.name		= CTU_NAME,
169
	.probe		= rsnd_ctu_probe_,
170 171
	.init		= rsnd_ctu_init,
	.quit		= rsnd_ctu_quit,
172
	.hw_params	= rsnd_ctu_hw_params,
173 174 175 176 177 178 179
};

struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
{
	if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv)))
		id = 0;

180
	return rsnd_mod_get(rsnd_ctu_get(priv, id));
181 182
}

183
int rsnd_ctu_probe(struct rsnd_priv *priv)
184
{
185 186
	struct device_node *node;
	struct device_node *np;
187 188 189 190 191 192 193
	struct device *dev = rsnd_priv_to_dev(priv);
	struct rsnd_ctu *ctu;
	struct clk *clk;
	char name[CTU_NAME_SIZE];
	int i, nr, ret;

	/* This driver doesn't support Gen1 at this point */
194 195
	if (rsnd_is_gen1(priv))
		return 0;
196

197 198 199
	node = rsnd_ctu_of_node(priv);
	if (!node)
		return 0; /* not used is not error */
200

201 202 203 204 205
	nr = of_get_child_count(node);
	if (!nr) {
		ret = -EINVAL;
		goto rsnd_ctu_probe_done;
	}
206 207

	ctu = devm_kzalloc(dev, sizeof(*ctu) * nr, GFP_KERNEL);
208 209 210 211
	if (!ctu) {
		ret = -ENOMEM;
		goto rsnd_ctu_probe_done;
	}
212 213 214 215

	priv->ctu_nr	= nr;
	priv->ctu	= ctu;

216
	i = 0;
217
	ret = 0;
218 219 220
	for_each_child_of_node(node, np) {
		ctu = rsnd_ctu_get(priv, i);

221 222 223 224 225 226 227 228
		/*
		 * CTU00, CTU01, CTU02, CTU03 => CTU0
		 * CTU10, CTU11, CTU12, CTU13 => CTU1
		 */
		snprintf(name, CTU_NAME_SIZE, "%s.%d",
			 CTU_NAME, i / 4);

		clk = devm_clk_get(dev, name);
229 230 231 232
		if (IS_ERR(clk)) {
			ret = PTR_ERR(clk);
			goto rsnd_ctu_probe_done;
		}
233

234
		ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
235
				    clk, rsnd_mod_get_status, RSND_MOD_CTU, i);
236
		if (ret)
237 238 239
			goto rsnd_ctu_probe_done;

		i++;
240 241
	}

242 243 244 245 246

rsnd_ctu_probe_done:
	of_node_put(node);

	return ret;
247 248
}

249
void rsnd_ctu_remove(struct rsnd_priv *priv)
250 251 252 253 254
{
	struct rsnd_ctu *ctu;
	int i;

	for_each_rsnd_ctu(ctu, priv, i) {
255
		rsnd_mod_quit(rsnd_mod_get(ctu));
256 257
	}
}