xref: /openbmc/linux/sound/soc/sh/rcar/gen.c (revision 07539c1d)
13337744aSKuninori Morimoto /*
23337744aSKuninori Morimoto  * Renesas R-Car Gen1 SRU/SSI support
33337744aSKuninori Morimoto  *
43337744aSKuninori Morimoto  * Copyright (C) 2013 Renesas Solutions Corp.
53337744aSKuninori Morimoto  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
63337744aSKuninori Morimoto  *
73337744aSKuninori Morimoto  * This program is free software; you can redistribute it and/or modify
83337744aSKuninori Morimoto  * it under the terms of the GNU General Public License version 2 as
93337744aSKuninori Morimoto  * published by the Free Software Foundation.
103337744aSKuninori Morimoto  */
113337744aSKuninori Morimoto #include "rsnd.h"
123337744aSKuninori Morimoto 
133337744aSKuninori Morimoto struct rsnd_gen_ops {
143337744aSKuninori Morimoto 	int (*path_init)(struct rsnd_priv *priv,
153337744aSKuninori Morimoto 			 struct rsnd_dai *rdai,
163337744aSKuninori Morimoto 			 struct rsnd_dai_stream *io);
173337744aSKuninori Morimoto 	int (*path_exit)(struct rsnd_priv *priv,
183337744aSKuninori Morimoto 			 struct rsnd_dai *rdai,
193337744aSKuninori Morimoto 			 struct rsnd_dai_stream *io);
203337744aSKuninori Morimoto };
213337744aSKuninori Morimoto 
223337744aSKuninori Morimoto struct rsnd_gen_reg_map {
233337744aSKuninori Morimoto 	int index;	/* -1 : not supported */
243337744aSKuninori Morimoto 	u32 offset_id;	/* offset of ssi0, ssi1, ssi2... */
253337744aSKuninori Morimoto 	u32 offset_adr;	/* offset of SSICR, SSISR, ... */
263337744aSKuninori Morimoto };
273337744aSKuninori Morimoto 
283337744aSKuninori Morimoto struct rsnd_gen {
293337744aSKuninori Morimoto 	void __iomem *base[RSND_BASE_MAX];
303337744aSKuninori Morimoto 
313337744aSKuninori Morimoto 	struct rsnd_gen_reg_map reg_map[RSND_REG_MAX];
323337744aSKuninori Morimoto 	struct rsnd_gen_ops *ops;
333337744aSKuninori Morimoto };
343337744aSKuninori Morimoto 
353337744aSKuninori Morimoto #define rsnd_priv_to_gen(p)	((struct rsnd_gen *)(p)->gen)
363337744aSKuninori Morimoto 
373337744aSKuninori Morimoto #define rsnd_is_gen1(s)		((s)->info->flags & RSND_GEN1)
383337744aSKuninori Morimoto #define rsnd_is_gen2(s)		((s)->info->flags & RSND_GEN2)
393337744aSKuninori Morimoto 
403337744aSKuninori Morimoto /*
413337744aSKuninori Morimoto  *		Gen2
423337744aSKuninori Morimoto  *		will be filled in the future
433337744aSKuninori Morimoto  */
443337744aSKuninori Morimoto 
453337744aSKuninori Morimoto /*
463337744aSKuninori Morimoto  *		Gen1
473337744aSKuninori Morimoto  */
4807539c1dSKuninori Morimoto static int rsnd_gen1_path_init(struct rsnd_priv *priv,
4907539c1dSKuninori Morimoto 			       struct rsnd_dai *rdai,
5007539c1dSKuninori Morimoto 			       struct rsnd_dai_stream *io)
5107539c1dSKuninori Morimoto {
5207539c1dSKuninori Morimoto 	struct rsnd_dai_platform_info *info = rsnd_dai_get_platform_info(rdai);
5307539c1dSKuninori Morimoto 	struct rsnd_mod *mod;
5407539c1dSKuninori Morimoto 	int ret;
5507539c1dSKuninori Morimoto 	int id;
5607539c1dSKuninori Morimoto 
5707539c1dSKuninori Morimoto 	/*
5807539c1dSKuninori Morimoto 	 * Gen1 is created by SRU/SSI, and this SRU is base module of
5907539c1dSKuninori Morimoto 	 * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU)
6007539c1dSKuninori Morimoto 	 *
6107539c1dSKuninori Morimoto 	 * Easy image is..
6207539c1dSKuninori Morimoto 	 *	Gen1 SRU = Gen2 SCU + SSIU + etc
6307539c1dSKuninori Morimoto 	 *
6407539c1dSKuninori Morimoto 	 * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
6507539c1dSKuninori Morimoto 	 * using fixed path.
6607539c1dSKuninori Morimoto 	 *
6707539c1dSKuninori Morimoto 	 * Then, SSI id = SCU id here
6807539c1dSKuninori Morimoto 	 */
6907539c1dSKuninori Morimoto 
7007539c1dSKuninori Morimoto 	if (rsnd_dai_is_play(rdai, io))
7107539c1dSKuninori Morimoto 		id = info->ssi_id_playback;
7207539c1dSKuninori Morimoto 	else
7307539c1dSKuninori Morimoto 		id = info->ssi_id_capture;
7407539c1dSKuninori Morimoto 
7507539c1dSKuninori Morimoto 	/* SCU */
7607539c1dSKuninori Morimoto 	mod = rsnd_scu_mod_get(priv, id);
7707539c1dSKuninori Morimoto 	ret = rsnd_dai_connect(rdai, mod, io);
7807539c1dSKuninori Morimoto 
7907539c1dSKuninori Morimoto 	return ret;
8007539c1dSKuninori Morimoto }
8107539c1dSKuninori Morimoto 
8207539c1dSKuninori Morimoto static int rsnd_gen1_path_exit(struct rsnd_priv *priv,
8307539c1dSKuninori Morimoto 			       struct rsnd_dai *rdai,
8407539c1dSKuninori Morimoto 			       struct rsnd_dai_stream *io)
8507539c1dSKuninori Morimoto {
8607539c1dSKuninori Morimoto 	struct rsnd_mod *mod, *n;
8707539c1dSKuninori Morimoto 	int ret = 0;
8807539c1dSKuninori Morimoto 
8907539c1dSKuninori Morimoto 	/*
9007539c1dSKuninori Morimoto 	 * remove all mod from rdai
9107539c1dSKuninori Morimoto 	 */
9207539c1dSKuninori Morimoto 	for_each_rsnd_mod(mod, n, io)
9307539c1dSKuninori Morimoto 		ret |= rsnd_dai_disconnect(mod);
9407539c1dSKuninori Morimoto 
9507539c1dSKuninori Morimoto 	return ret;
9607539c1dSKuninori Morimoto }
9707539c1dSKuninori Morimoto 
9807539c1dSKuninori Morimoto static struct rsnd_gen_ops rsnd_gen1_ops = {
9907539c1dSKuninori Morimoto 	.path_init	= rsnd_gen1_path_init,
10007539c1dSKuninori Morimoto 	.path_exit	= rsnd_gen1_path_exit,
10107539c1dSKuninori Morimoto };
10207539c1dSKuninori Morimoto 
10307539c1dSKuninori Morimoto #define RSND_GEN1_REG_MAP(g, s, i, oi, oa)				\
10407539c1dSKuninori Morimoto 	do {								\
10507539c1dSKuninori Morimoto 		(g)->reg_map[RSND_REG_##i].index  = RSND_GEN1_##s;	\
10607539c1dSKuninori Morimoto 		(g)->reg_map[RSND_REG_##i].offset_id = oi;		\
10707539c1dSKuninori Morimoto 		(g)->reg_map[RSND_REG_##i].offset_adr = oa;		\
10807539c1dSKuninori Morimoto 	} while (0)
10907539c1dSKuninori Morimoto 
11007539c1dSKuninori Morimoto static void rsnd_gen1_reg_map_init(struct rsnd_gen *gen)
11107539c1dSKuninori Morimoto {
11207539c1dSKuninori Morimoto 	RSND_GEN1_REG_MAP(gen, SRU,	SSI_MODE0,	0x0,	0xD0);
11307539c1dSKuninori Morimoto 	RSND_GEN1_REG_MAP(gen, SRU,	SSI_MODE1,	0x0,	0xD4);
11407539c1dSKuninori Morimoto }
11507539c1dSKuninori Morimoto 
1163337744aSKuninori Morimoto static int rsnd_gen1_probe(struct platform_device *pdev,
1173337744aSKuninori Morimoto 			   struct rcar_snd_info *info,
1183337744aSKuninori Morimoto 			   struct rsnd_priv *priv)
1193337744aSKuninori Morimoto {
12007539c1dSKuninori Morimoto 	struct device *dev = rsnd_priv_to_dev(priv);
12107539c1dSKuninori Morimoto 	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
12207539c1dSKuninori Morimoto 	struct resource *sru_res;
12307539c1dSKuninori Morimoto 
12407539c1dSKuninori Morimoto 	/*
12507539c1dSKuninori Morimoto 	 * map address
12607539c1dSKuninori Morimoto 	 */
12707539c1dSKuninori Morimoto 	sru_res	= platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU);
12807539c1dSKuninori Morimoto 	if (!sru_res) {
12907539c1dSKuninori Morimoto 		dev_err(dev, "Not enough SRU/SSI/ADG platform resources.\n");
13007539c1dSKuninori Morimoto 		return -ENODEV;
13107539c1dSKuninori Morimoto 	}
13207539c1dSKuninori Morimoto 
13307539c1dSKuninori Morimoto 	gen->ops = &rsnd_gen1_ops;
13407539c1dSKuninori Morimoto 
13507539c1dSKuninori Morimoto 	gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res);
13607539c1dSKuninori Morimoto 	if (!gen->base[RSND_GEN1_SRU]) {
13707539c1dSKuninori Morimoto 		dev_err(dev, "SRU/SSI/ADG ioremap failed\n");
13807539c1dSKuninori Morimoto 		return -ENODEV;
13907539c1dSKuninori Morimoto 	}
14007539c1dSKuninori Morimoto 
14107539c1dSKuninori Morimoto 	rsnd_gen1_reg_map_init(gen);
14207539c1dSKuninori Morimoto 
14307539c1dSKuninori Morimoto 	dev_dbg(dev, "Gen1 device probed\n");
14407539c1dSKuninori Morimoto 	dev_dbg(dev, "SRU : %08x => %p\n",	sru_res->start,
14507539c1dSKuninori Morimoto 						gen->base[RSND_GEN1_SRU]);
14607539c1dSKuninori Morimoto 
1473337744aSKuninori Morimoto 	return 0;
1483337744aSKuninori Morimoto }
1493337744aSKuninori Morimoto 
1503337744aSKuninori Morimoto static void rsnd_gen1_remove(struct platform_device *pdev,
1513337744aSKuninori Morimoto 			     struct rsnd_priv *priv)
1523337744aSKuninori Morimoto {
1533337744aSKuninori Morimoto }
1543337744aSKuninori Morimoto 
1553337744aSKuninori Morimoto /*
1563337744aSKuninori Morimoto  *		Gen
1573337744aSKuninori Morimoto  */
1583337744aSKuninori Morimoto int rsnd_gen_path_init(struct rsnd_priv *priv,
1593337744aSKuninori Morimoto 		       struct rsnd_dai *rdai,
1603337744aSKuninori Morimoto 		       struct rsnd_dai_stream *io)
1613337744aSKuninori Morimoto {
1623337744aSKuninori Morimoto 	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
1633337744aSKuninori Morimoto 
1643337744aSKuninori Morimoto 	return gen->ops->path_init(priv, rdai, io);
1653337744aSKuninori Morimoto }
1663337744aSKuninori Morimoto 
1673337744aSKuninori Morimoto int rsnd_gen_path_exit(struct rsnd_priv *priv,
1683337744aSKuninori Morimoto 		       struct rsnd_dai *rdai,
1693337744aSKuninori Morimoto 		       struct rsnd_dai_stream *io)
1703337744aSKuninori Morimoto {
1713337744aSKuninori Morimoto 	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
1723337744aSKuninori Morimoto 
1733337744aSKuninori Morimoto 	return gen->ops->path_exit(priv, rdai, io);
1743337744aSKuninori Morimoto }
1753337744aSKuninori Morimoto 
1763337744aSKuninori Morimoto void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
1773337744aSKuninori Morimoto 			       struct rsnd_mod *mod,
1783337744aSKuninori Morimoto 			       enum rsnd_reg reg)
1793337744aSKuninori Morimoto {
1803337744aSKuninori Morimoto 	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
1813337744aSKuninori Morimoto 	struct device *dev = rsnd_priv_to_dev(priv);
1823337744aSKuninori Morimoto 	int index;
1833337744aSKuninori Morimoto 	u32 offset_id, offset_adr;
1843337744aSKuninori Morimoto 
1853337744aSKuninori Morimoto 	if (reg >= RSND_REG_MAX) {
1863337744aSKuninori Morimoto 		dev_err(dev, "rsnd_reg reg error\n");
1873337744aSKuninori Morimoto 		return NULL;
1883337744aSKuninori Morimoto 	}
1893337744aSKuninori Morimoto 
1903337744aSKuninori Morimoto 	index		= gen->reg_map[reg].index;
1913337744aSKuninori Morimoto 	offset_id	= gen->reg_map[reg].offset_id;
1923337744aSKuninori Morimoto 	offset_adr	= gen->reg_map[reg].offset_adr;
1933337744aSKuninori Morimoto 
1943337744aSKuninori Morimoto 	if (index < 0) {
1953337744aSKuninori Morimoto 		dev_err(dev, "unsupported reg access %d\n", reg);
1963337744aSKuninori Morimoto 		return NULL;
1973337744aSKuninori Morimoto 	}
1983337744aSKuninori Morimoto 
1993337744aSKuninori Morimoto 	if (offset_id && mod)
2003337744aSKuninori Morimoto 		offset_id *= rsnd_mod_id(mod);
2013337744aSKuninori Morimoto 
2023337744aSKuninori Morimoto 	/*
2033337744aSKuninori Morimoto 	 * index/offset were set on gen1/gen2
2043337744aSKuninori Morimoto 	 */
2053337744aSKuninori Morimoto 
2063337744aSKuninori Morimoto 	return gen->base[index] + offset_id + offset_adr;
2073337744aSKuninori Morimoto }
2083337744aSKuninori Morimoto 
2093337744aSKuninori Morimoto int rsnd_gen_probe(struct platform_device *pdev,
2103337744aSKuninori Morimoto 		   struct rcar_snd_info *info,
2113337744aSKuninori Morimoto 		   struct rsnd_priv *priv)
2123337744aSKuninori Morimoto {
2133337744aSKuninori Morimoto 	struct device *dev = rsnd_priv_to_dev(priv);
2143337744aSKuninori Morimoto 	struct rsnd_gen *gen;
2153337744aSKuninori Morimoto 	int i;
2163337744aSKuninori Morimoto 
2173337744aSKuninori Morimoto 	gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
2183337744aSKuninori Morimoto 	if (!gen) {
2193337744aSKuninori Morimoto 		dev_err(dev, "GEN allocate failed\n");
2203337744aSKuninori Morimoto 		return -ENOMEM;
2213337744aSKuninori Morimoto 	}
2223337744aSKuninori Morimoto 
2233337744aSKuninori Morimoto 	priv->gen = gen;
2243337744aSKuninori Morimoto 
2253337744aSKuninori Morimoto 	/*
2263337744aSKuninori Morimoto 	 * see
2273337744aSKuninori Morimoto 	 *	rsnd_reg_get()
2283337744aSKuninori Morimoto 	 *	rsnd_gen_probe()
2293337744aSKuninori Morimoto 	 */
2303337744aSKuninori Morimoto 	for (i = 0; i < RSND_REG_MAX; i++)
2313337744aSKuninori Morimoto 		gen->reg_map[i].index = -1;
2323337744aSKuninori Morimoto 
2333337744aSKuninori Morimoto 	/*
2343337744aSKuninori Morimoto 	 *	init each module
2353337744aSKuninori Morimoto 	 */
2363337744aSKuninori Morimoto 	if (rsnd_is_gen1(priv))
2373337744aSKuninori Morimoto 		return rsnd_gen1_probe(pdev, info, priv);
2383337744aSKuninori Morimoto 
2393337744aSKuninori Morimoto 	dev_err(dev, "unknown generation R-Car sound device\n");
2403337744aSKuninori Morimoto 
2413337744aSKuninori Morimoto 	return -ENODEV;
2423337744aSKuninori Morimoto }
2433337744aSKuninori Morimoto 
2443337744aSKuninori Morimoto void rsnd_gen_remove(struct platform_device *pdev,
2453337744aSKuninori Morimoto 		     struct rsnd_priv *priv)
2463337744aSKuninori Morimoto {
2473337744aSKuninori Morimoto 	if (rsnd_is_gen1(priv))
2483337744aSKuninori Morimoto 		rsnd_gen1_remove(pdev, priv);
2493337744aSKuninori Morimoto }
250