gen.c 7.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * Renesas R-Car Gen1 SRU/SSI support
 *
 * Copyright (C) 2013 Renesas Solutions Corp.
 * 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"

struct rsnd_gen_ops {
14 15 16 17 18
	int (*probe)(struct platform_device *pdev,
		     struct rcar_snd_info *info,
		     struct rsnd_priv *priv);
	void (*remove)(struct platform_device *pdev,
		      struct rsnd_priv *priv);
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
	int (*path_init)(struct rsnd_priv *priv,
			 struct rsnd_dai *rdai,
			 struct rsnd_dai_stream *io);
	int (*path_exit)(struct rsnd_priv *priv,
			 struct rsnd_dai *rdai,
			 struct rsnd_dai_stream *io);
};

struct rsnd_gen_reg_map {
	int index;	/* -1 : not supported */
	u32 offset_id;	/* offset of ssi0, ssi1, ssi2... */
	u32 offset_adr;	/* offset of SSICR, SSISR, ... */
};

struct rsnd_gen {
	void __iomem *base[RSND_BASE_MAX];

	struct rsnd_gen_reg_map reg_map[RSND_REG_MAX];
	struct rsnd_gen_ops *ops;
};

#define rsnd_priv_to_gen(p)	((struct rsnd_gen *)(p)->gen)

/*
 *		Gen2
 *		will be filled in the future
 */

/*
 *		Gen1
 */
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
static int rsnd_gen1_path_init(struct rsnd_priv *priv,
			       struct rsnd_dai *rdai,
			       struct rsnd_dai_stream *io)
{
	struct rsnd_mod *mod;
	int ret;
	int id;

	/*
	 * Gen1 is created by SRU/SSI, and this SRU is base module of
	 * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU)
	 *
	 * Easy image is..
	 *	Gen1 SRU = Gen2 SCU + SSIU + etc
	 *
	 * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
	 * using fixed path.
	 *
	 * Then, SSI id = SCU id here
	 */

71 72 73 74 75
	/* get SSI's ID */
	mod = rsnd_ssi_mod_get_frm_dai(priv,
				       rsnd_dai_id(priv, rdai),
				       rsnd_dai_is_play(rdai, io));
	id = rsnd_mod_id(mod);
76

77 78 79 80 81 82
	/* SSI */
	mod = rsnd_ssi_mod_get(priv, id);
	ret = rsnd_dai_connect(rdai, mod, io);
	if (ret < 0)
		return ret;

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
	/* SCU */
	mod = rsnd_scu_mod_get(priv, id);
	ret = rsnd_dai_connect(rdai, mod, io);

	return ret;
}

static int rsnd_gen1_path_exit(struct rsnd_priv *priv,
			       struct rsnd_dai *rdai,
			       struct rsnd_dai_stream *io)
{
	struct rsnd_mod *mod, *n;
	int ret = 0;

	/*
	 * remove all mod from rdai
	 */
	for_each_rsnd_mod(mod, n, io)
		ret |= rsnd_dai_disconnect(mod);

	return ret;
}

#define RSND_GEN1_REG_MAP(g, s, i, oi, oa)				\
	do {								\
		(g)->reg_map[RSND_REG_##i].index  = RSND_GEN1_##s;	\
		(g)->reg_map[RSND_REG_##i].offset_id = oi;		\
		(g)->reg_map[RSND_REG_##i].offset_adr = oa;		\
	} while (0)

static void rsnd_gen1_reg_map_init(struct rsnd_gen *gen)
{
115 116 117 118 119
	RSND_GEN1_REG_MAP(gen, SRU,	SRC_ROUTE_SEL,	0x0,	0x00);
	RSND_GEN1_REG_MAP(gen, SRU,	SRC_TMG_SEL0,	0x0,	0x08);
	RSND_GEN1_REG_MAP(gen, SRU,	SRC_TMG_SEL1,	0x0,	0x0c);
	RSND_GEN1_REG_MAP(gen, SRU,	SRC_TMG_SEL2,	0x0,	0x10);
	RSND_GEN1_REG_MAP(gen, SRU,	SRC_CTRL,	0x0,	0xc0);
120 121
	RSND_GEN1_REG_MAP(gen, SRU,	SSI_MODE0,	0x0,	0xD0);
	RSND_GEN1_REG_MAP(gen, SRU,	SSI_MODE1,	0x0,	0xD4);
122 123
	RSND_GEN1_REG_MAP(gen, SRU,	BUSIF_MODE,	0x4,	0x20);
	RSND_GEN1_REG_MAP(gen, SRU,	BUSIF_ADINR,	0x40,	0x214);
124 125 126 127 128 129 130 131 132

	RSND_GEN1_REG_MAP(gen, ADG,	BRRA,		0x0,	0x00);
	RSND_GEN1_REG_MAP(gen, ADG,	BRRB,		0x0,	0x04);
	RSND_GEN1_REG_MAP(gen, ADG,	SSICKR,		0x0,	0x08);
	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL0,	0x0,	0x0c);
	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL1,	0x0,	0x10);
	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL3,	0x0,	0x18);
	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL4,	0x0,	0x1c);
	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL5,	0x0,	0x20);
133 134 135 136 137 138

	RSND_GEN1_REG_MAP(gen, SSI,	SSICR,		0x40,	0x00);
	RSND_GEN1_REG_MAP(gen, SSI,	SSISR,		0x40,	0x04);
	RSND_GEN1_REG_MAP(gen, SSI,	SSITDR,		0x40,	0x08);
	RSND_GEN1_REG_MAP(gen, SSI,	SSIRDR,		0x40,	0x0c);
	RSND_GEN1_REG_MAP(gen, SSI,	SSIWSR,		0x40,	0x20);
139 140
}

141 142 143 144
static int rsnd_gen1_probe(struct platform_device *pdev,
			   struct rcar_snd_info *info,
			   struct rsnd_priv *priv)
{
145 146 147
	struct device *dev = rsnd_priv_to_dev(priv);
	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
	struct resource *sru_res;
148
	struct resource *adg_res;
149
	struct resource *ssi_res;
150 151 152 153 154

	/*
	 * map address
	 */
	sru_res	= platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU);
155
	adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_ADG);
156
	ssi_res	= platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SSI);
157 158

	gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res);
159
	gen->base[RSND_GEN1_ADG] = devm_ioremap_resource(dev, adg_res);
160
	gen->base[RSND_GEN1_SSI] = devm_ioremap_resource(dev, ssi_res);
161 162 163
	if (IS_ERR(gen->base[RSND_GEN1_SRU]) ||
	    IS_ERR(gen->base[RSND_GEN1_ADG]) ||
	    IS_ERR(gen->base[RSND_GEN1_SSI]))
164 165 166 167 168 169 170
		return -ENODEV;

	rsnd_gen1_reg_map_init(gen);

	dev_dbg(dev, "Gen1 device probed\n");
	dev_dbg(dev, "SRU : %08x => %p\n",	sru_res->start,
						gen->base[RSND_GEN1_SRU]);
171 172
	dev_dbg(dev, "ADG : %08x => %p\n",	adg_res->start,
						gen->base[RSND_GEN1_ADG]);
173 174
	dev_dbg(dev, "SSI : %08x => %p\n",	ssi_res->start,
						gen->base[RSND_GEN1_SSI]);
175

176
	return 0;
177

178 179 180 181 182 183 184
}

static void rsnd_gen1_remove(struct platform_device *pdev,
			     struct rsnd_priv *priv)
{
}

185 186 187 188 189 190 191
static struct rsnd_gen_ops rsnd_gen1_ops = {
	.probe		= rsnd_gen1_probe,
	.remove		= rsnd_gen1_remove,
	.path_init	= rsnd_gen1_path_init,
	.path_exit	= rsnd_gen1_path_exit,
};

192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
/*
 *		Gen
 */
int rsnd_gen_path_init(struct rsnd_priv *priv,
		       struct rsnd_dai *rdai,
		       struct rsnd_dai_stream *io)
{
	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);

	return gen->ops->path_init(priv, rdai, io);
}

int rsnd_gen_path_exit(struct rsnd_priv *priv,
		       struct rsnd_dai *rdai,
		       struct rsnd_dai_stream *io)
{
	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);

	return gen->ops->path_exit(priv, rdai, io);
}

void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
			       struct rsnd_mod *mod,
			       enum rsnd_reg reg)
{
	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
	struct device *dev = rsnd_priv_to_dev(priv);
	int index;
	u32 offset_id, offset_adr;

	if (reg >= RSND_REG_MAX) {
		dev_err(dev, "rsnd_reg reg error\n");
		return NULL;
	}

	index		= gen->reg_map[reg].index;
	offset_id	= gen->reg_map[reg].offset_id;
	offset_adr	= gen->reg_map[reg].offset_adr;

	if (index < 0) {
		dev_err(dev, "unsupported reg access %d\n", reg);
		return NULL;
	}

	if (offset_id && mod)
		offset_id *= rsnd_mod_id(mod);

	/*
	 * index/offset were set on gen1/gen2
	 */

	return gen->base[index] + offset_id + offset_adr;
}

int rsnd_gen_probe(struct platform_device *pdev,
		   struct rcar_snd_info *info,
		   struct rsnd_priv *priv)
{
	struct device *dev = rsnd_priv_to_dev(priv);
	struct rsnd_gen *gen;
	int i;

	gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
	if (!gen) {
		dev_err(dev, "GEN allocate failed\n");
		return -ENOMEM;
	}

260 261 262 263 264 265 266 267
	if (rsnd_is_gen1(priv))
		gen->ops = &rsnd_gen1_ops;

	if (!gen->ops) {
		dev_err(dev, "unknown generation R-Car sound device\n");
		return -ENODEV;
	}

268 269 270 271 272 273 274 275 276 277
	priv->gen = gen;

	/*
	 * see
	 *	rsnd_reg_get()
	 *	rsnd_gen_probe()
	 */
	for (i = 0; i < RSND_REG_MAX; i++)
		gen->reg_map[i].index = -1;

278
	return gen->ops->probe(pdev, info, priv);
279 280 281 282 283
}

void rsnd_gen_remove(struct platform_device *pdev,
		     struct rsnd_priv *priv)
{
284 285 286
	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);

	gen->ops->remove(pdev, priv);
287
}