xref: /openbmc/linux/sound/soc/sh/rcar/gen.c (revision 4b4dab82)
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_mod *mod;
5307539c1dSKuninori Morimoto 	int ret;
5407539c1dSKuninori Morimoto 	int id;
5507539c1dSKuninori Morimoto 
5607539c1dSKuninori Morimoto 	/*
5707539c1dSKuninori Morimoto 	 * Gen1 is created by SRU/SSI, and this SRU is base module of
5807539c1dSKuninori Morimoto 	 * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU)
5907539c1dSKuninori Morimoto 	 *
6007539c1dSKuninori Morimoto 	 * Easy image is..
6107539c1dSKuninori Morimoto 	 *	Gen1 SRU = Gen2 SCU + SSIU + etc
6207539c1dSKuninori Morimoto 	 *
6307539c1dSKuninori Morimoto 	 * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
6407539c1dSKuninori Morimoto 	 * using fixed path.
6507539c1dSKuninori Morimoto 	 *
6607539c1dSKuninori Morimoto 	 * Then, SSI id = SCU id here
6707539c1dSKuninori Morimoto 	 */
6807539c1dSKuninori Morimoto 
694b4dab82SKuninori Morimoto 	/* get SSI's ID */
704b4dab82SKuninori Morimoto 	mod = rsnd_ssi_mod_get_frm_dai(priv,
714b4dab82SKuninori Morimoto 				       rsnd_dai_id(priv, rdai),
724b4dab82SKuninori Morimoto 				       rsnd_dai_is_play(rdai, io));
734b4dab82SKuninori Morimoto 	id = rsnd_mod_id(mod);
7407539c1dSKuninori Morimoto 
75ae5c3223SKuninori Morimoto 	/* SSI */
76ae5c3223SKuninori Morimoto 	mod = rsnd_ssi_mod_get(priv, id);
77ae5c3223SKuninori Morimoto 	ret = rsnd_dai_connect(rdai, mod, io);
78ae5c3223SKuninori Morimoto 	if (ret < 0)
79ae5c3223SKuninori Morimoto 		return ret;
80ae5c3223SKuninori Morimoto 
8107539c1dSKuninori Morimoto 	/* SCU */
8207539c1dSKuninori Morimoto 	mod = rsnd_scu_mod_get(priv, id);
8307539c1dSKuninori Morimoto 	ret = rsnd_dai_connect(rdai, mod, io);
8407539c1dSKuninori Morimoto 
8507539c1dSKuninori Morimoto 	return ret;
8607539c1dSKuninori Morimoto }
8707539c1dSKuninori Morimoto 
8807539c1dSKuninori Morimoto static int rsnd_gen1_path_exit(struct rsnd_priv *priv,
8907539c1dSKuninori Morimoto 			       struct rsnd_dai *rdai,
9007539c1dSKuninori Morimoto 			       struct rsnd_dai_stream *io)
9107539c1dSKuninori Morimoto {
9207539c1dSKuninori Morimoto 	struct rsnd_mod *mod, *n;
9307539c1dSKuninori Morimoto 	int ret = 0;
9407539c1dSKuninori Morimoto 
9507539c1dSKuninori Morimoto 	/*
9607539c1dSKuninori Morimoto 	 * remove all mod from rdai
9707539c1dSKuninori Morimoto 	 */
9807539c1dSKuninori Morimoto 	for_each_rsnd_mod(mod, n, io)
9907539c1dSKuninori Morimoto 		ret |= rsnd_dai_disconnect(mod);
10007539c1dSKuninori Morimoto 
10107539c1dSKuninori Morimoto 	return ret;
10207539c1dSKuninori Morimoto }
10307539c1dSKuninori Morimoto 
10407539c1dSKuninori Morimoto static struct rsnd_gen_ops rsnd_gen1_ops = {
10507539c1dSKuninori Morimoto 	.path_init	= rsnd_gen1_path_init,
10607539c1dSKuninori Morimoto 	.path_exit	= rsnd_gen1_path_exit,
10707539c1dSKuninori Morimoto };
10807539c1dSKuninori Morimoto 
10907539c1dSKuninori Morimoto #define RSND_GEN1_REG_MAP(g, s, i, oi, oa)				\
11007539c1dSKuninori Morimoto 	do {								\
11107539c1dSKuninori Morimoto 		(g)->reg_map[RSND_REG_##i].index  = RSND_GEN1_##s;	\
11207539c1dSKuninori Morimoto 		(g)->reg_map[RSND_REG_##i].offset_id = oi;		\
11307539c1dSKuninori Morimoto 		(g)->reg_map[RSND_REG_##i].offset_adr = oa;		\
11407539c1dSKuninori Morimoto 	} while (0)
11507539c1dSKuninori Morimoto 
11607539c1dSKuninori Morimoto static void rsnd_gen1_reg_map_init(struct rsnd_gen *gen)
11707539c1dSKuninori Morimoto {
11807539c1dSKuninori Morimoto 	RSND_GEN1_REG_MAP(gen, SRU,	SSI_MODE0,	0x0,	0xD0);
11907539c1dSKuninori Morimoto 	RSND_GEN1_REG_MAP(gen, SRU,	SSI_MODE1,	0x0,	0xD4);
120dfc9403bSKuninori Morimoto 
121dfc9403bSKuninori Morimoto 	RSND_GEN1_REG_MAP(gen, ADG,	BRRA,		0x0,	0x00);
122dfc9403bSKuninori Morimoto 	RSND_GEN1_REG_MAP(gen, ADG,	BRRB,		0x0,	0x04);
123dfc9403bSKuninori Morimoto 	RSND_GEN1_REG_MAP(gen, ADG,	SSICKR,		0x0,	0x08);
124dfc9403bSKuninori Morimoto 	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL0,	0x0,	0x0c);
125dfc9403bSKuninori Morimoto 	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL1,	0x0,	0x10);
126dfc9403bSKuninori Morimoto 	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL3,	0x0,	0x18);
127dfc9403bSKuninori Morimoto 	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL4,	0x0,	0x1c);
128dfc9403bSKuninori Morimoto 	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL5,	0x0,	0x20);
129ae5c3223SKuninori Morimoto 
130ae5c3223SKuninori Morimoto 	RSND_GEN1_REG_MAP(gen, SSI,	SSICR,		0x40,	0x00);
131ae5c3223SKuninori Morimoto 	RSND_GEN1_REG_MAP(gen, SSI,	SSISR,		0x40,	0x04);
132ae5c3223SKuninori Morimoto 	RSND_GEN1_REG_MAP(gen, SSI,	SSITDR,		0x40,	0x08);
133ae5c3223SKuninori Morimoto 	RSND_GEN1_REG_MAP(gen, SSI,	SSIRDR,		0x40,	0x0c);
134ae5c3223SKuninori Morimoto 	RSND_GEN1_REG_MAP(gen, SSI,	SSIWSR,		0x40,	0x20);
13507539c1dSKuninori Morimoto }
13607539c1dSKuninori Morimoto 
1373337744aSKuninori Morimoto static int rsnd_gen1_probe(struct platform_device *pdev,
1383337744aSKuninori Morimoto 			   struct rcar_snd_info *info,
1393337744aSKuninori Morimoto 			   struct rsnd_priv *priv)
1403337744aSKuninori Morimoto {
14107539c1dSKuninori Morimoto 	struct device *dev = rsnd_priv_to_dev(priv);
14207539c1dSKuninori Morimoto 	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
14307539c1dSKuninori Morimoto 	struct resource *sru_res;
144dfc9403bSKuninori Morimoto 	struct resource *adg_res;
145ae5c3223SKuninori Morimoto 	struct resource *ssi_res;
14607539c1dSKuninori Morimoto 
14707539c1dSKuninori Morimoto 	/*
14807539c1dSKuninori Morimoto 	 * map address
14907539c1dSKuninori Morimoto 	 */
15007539c1dSKuninori Morimoto 	sru_res	= platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU);
151dfc9403bSKuninori Morimoto 	adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_ADG);
152ae5c3223SKuninori Morimoto 	ssi_res	= platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SSI);
15307539c1dSKuninori Morimoto 
15407539c1dSKuninori Morimoto 	gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res);
155dfc9403bSKuninori Morimoto 	gen->base[RSND_GEN1_ADG] = devm_ioremap_resource(dev, adg_res);
156ae5c3223SKuninori Morimoto 	gen->base[RSND_GEN1_SSI] = devm_ioremap_resource(dev, ssi_res);
15770263cb4SWei Yongjun 	if (IS_ERR(gen->base[RSND_GEN1_SRU]) ||
15870263cb4SWei Yongjun 	    IS_ERR(gen->base[RSND_GEN1_ADG]) ||
15970263cb4SWei Yongjun 	    IS_ERR(gen->base[RSND_GEN1_SSI]))
16007539c1dSKuninori Morimoto 		return -ENODEV;
16107539c1dSKuninori Morimoto 
16270263cb4SWei Yongjun 	gen->ops = &rsnd_gen1_ops;
16307539c1dSKuninori Morimoto 	rsnd_gen1_reg_map_init(gen);
16407539c1dSKuninori Morimoto 
16507539c1dSKuninori Morimoto 	dev_dbg(dev, "Gen1 device probed\n");
16607539c1dSKuninori Morimoto 	dev_dbg(dev, "SRU : %08x => %p\n",	sru_res->start,
16707539c1dSKuninori Morimoto 						gen->base[RSND_GEN1_SRU]);
168dfc9403bSKuninori Morimoto 	dev_dbg(dev, "ADG : %08x => %p\n",	adg_res->start,
169dfc9403bSKuninori Morimoto 						gen->base[RSND_GEN1_ADG]);
170ae5c3223SKuninori Morimoto 	dev_dbg(dev, "SSI : %08x => %p\n",	ssi_res->start,
171ae5c3223SKuninori Morimoto 						gen->base[RSND_GEN1_SSI]);
17207539c1dSKuninori Morimoto 
1733337744aSKuninori Morimoto 	return 0;
174ae5c3223SKuninori Morimoto 
1753337744aSKuninori Morimoto }
1763337744aSKuninori Morimoto 
1773337744aSKuninori Morimoto static void rsnd_gen1_remove(struct platform_device *pdev,
1783337744aSKuninori Morimoto 			     struct rsnd_priv *priv)
1793337744aSKuninori Morimoto {
1803337744aSKuninori Morimoto }
1813337744aSKuninori Morimoto 
1823337744aSKuninori Morimoto /*
1833337744aSKuninori Morimoto  *		Gen
1843337744aSKuninori Morimoto  */
1853337744aSKuninori Morimoto int rsnd_gen_path_init(struct rsnd_priv *priv,
1863337744aSKuninori Morimoto 		       struct rsnd_dai *rdai,
1873337744aSKuninori Morimoto 		       struct rsnd_dai_stream *io)
1883337744aSKuninori Morimoto {
1893337744aSKuninori Morimoto 	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
1903337744aSKuninori Morimoto 
1913337744aSKuninori Morimoto 	return gen->ops->path_init(priv, rdai, io);
1923337744aSKuninori Morimoto }
1933337744aSKuninori Morimoto 
1943337744aSKuninori Morimoto int rsnd_gen_path_exit(struct rsnd_priv *priv,
1953337744aSKuninori Morimoto 		       struct rsnd_dai *rdai,
1963337744aSKuninori Morimoto 		       struct rsnd_dai_stream *io)
1973337744aSKuninori Morimoto {
1983337744aSKuninori Morimoto 	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
1993337744aSKuninori Morimoto 
2003337744aSKuninori Morimoto 	return gen->ops->path_exit(priv, rdai, io);
2013337744aSKuninori Morimoto }
2023337744aSKuninori Morimoto 
2033337744aSKuninori Morimoto void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
2043337744aSKuninori Morimoto 			       struct rsnd_mod *mod,
2053337744aSKuninori Morimoto 			       enum rsnd_reg reg)
2063337744aSKuninori Morimoto {
2073337744aSKuninori Morimoto 	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
2083337744aSKuninori Morimoto 	struct device *dev = rsnd_priv_to_dev(priv);
2093337744aSKuninori Morimoto 	int index;
2103337744aSKuninori Morimoto 	u32 offset_id, offset_adr;
2113337744aSKuninori Morimoto 
2123337744aSKuninori Morimoto 	if (reg >= RSND_REG_MAX) {
2133337744aSKuninori Morimoto 		dev_err(dev, "rsnd_reg reg error\n");
2143337744aSKuninori Morimoto 		return NULL;
2153337744aSKuninori Morimoto 	}
2163337744aSKuninori Morimoto 
2173337744aSKuninori Morimoto 	index		= gen->reg_map[reg].index;
2183337744aSKuninori Morimoto 	offset_id	= gen->reg_map[reg].offset_id;
2193337744aSKuninori Morimoto 	offset_adr	= gen->reg_map[reg].offset_adr;
2203337744aSKuninori Morimoto 
2213337744aSKuninori Morimoto 	if (index < 0) {
2223337744aSKuninori Morimoto 		dev_err(dev, "unsupported reg access %d\n", reg);
2233337744aSKuninori Morimoto 		return NULL;
2243337744aSKuninori Morimoto 	}
2253337744aSKuninori Morimoto 
2263337744aSKuninori Morimoto 	if (offset_id && mod)
2273337744aSKuninori Morimoto 		offset_id *= rsnd_mod_id(mod);
2283337744aSKuninori Morimoto 
2293337744aSKuninori Morimoto 	/*
2303337744aSKuninori Morimoto 	 * index/offset were set on gen1/gen2
2313337744aSKuninori Morimoto 	 */
2323337744aSKuninori Morimoto 
2333337744aSKuninori Morimoto 	return gen->base[index] + offset_id + offset_adr;
2343337744aSKuninori Morimoto }
2353337744aSKuninori Morimoto 
2363337744aSKuninori Morimoto int rsnd_gen_probe(struct platform_device *pdev,
2373337744aSKuninori Morimoto 		   struct rcar_snd_info *info,
2383337744aSKuninori Morimoto 		   struct rsnd_priv *priv)
2393337744aSKuninori Morimoto {
2403337744aSKuninori Morimoto 	struct device *dev = rsnd_priv_to_dev(priv);
2413337744aSKuninori Morimoto 	struct rsnd_gen *gen;
2423337744aSKuninori Morimoto 	int i;
2433337744aSKuninori Morimoto 
2443337744aSKuninori Morimoto 	gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
2453337744aSKuninori Morimoto 	if (!gen) {
2463337744aSKuninori Morimoto 		dev_err(dev, "GEN allocate failed\n");
2473337744aSKuninori Morimoto 		return -ENOMEM;
2483337744aSKuninori Morimoto 	}
2493337744aSKuninori Morimoto 
2503337744aSKuninori Morimoto 	priv->gen = gen;
2513337744aSKuninori Morimoto 
2523337744aSKuninori Morimoto 	/*
2533337744aSKuninori Morimoto 	 * see
2543337744aSKuninori Morimoto 	 *	rsnd_reg_get()
2553337744aSKuninori Morimoto 	 *	rsnd_gen_probe()
2563337744aSKuninori Morimoto 	 */
2573337744aSKuninori Morimoto 	for (i = 0; i < RSND_REG_MAX; i++)
2583337744aSKuninori Morimoto 		gen->reg_map[i].index = -1;
2593337744aSKuninori Morimoto 
2603337744aSKuninori Morimoto 	/*
2613337744aSKuninori Morimoto 	 *	init each module
2623337744aSKuninori Morimoto 	 */
2633337744aSKuninori Morimoto 	if (rsnd_is_gen1(priv))
2643337744aSKuninori Morimoto 		return rsnd_gen1_probe(pdev, info, priv);
2653337744aSKuninori Morimoto 
2663337744aSKuninori Morimoto 	dev_err(dev, "unknown generation R-Car sound device\n");
2673337744aSKuninori Morimoto 
2683337744aSKuninori Morimoto 	return -ENODEV;
2693337744aSKuninori Morimoto }
2703337744aSKuninori Morimoto 
2713337744aSKuninori Morimoto void rsnd_gen_remove(struct platform_device *pdev,
2723337744aSKuninori Morimoto 		     struct rsnd_priv *priv)
2733337744aSKuninori Morimoto {
2743337744aSKuninori Morimoto 	if (rsnd_is_gen1(priv))
2753337744aSKuninori Morimoto 		rsnd_gen1_remove(pdev, priv);
2763337744aSKuninori Morimoto }
277