xref: /openbmc/linux/sound/soc/sh/rcar/gen.c (revision f7777dcc)
1 /*
2  * Renesas R-Car Gen1 SRU/SSI support
3  *
4  * Copyright (C) 2013 Renesas Solutions Corp.
5  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 #include "rsnd.h"
12 
13 struct rsnd_gen_ops {
14 	int (*path_init)(struct rsnd_priv *priv,
15 			 struct rsnd_dai *rdai,
16 			 struct rsnd_dai_stream *io);
17 	int (*path_exit)(struct rsnd_priv *priv,
18 			 struct rsnd_dai *rdai,
19 			 struct rsnd_dai_stream *io);
20 };
21 
22 struct rsnd_gen_reg_map {
23 	int index;	/* -1 : not supported */
24 	u32 offset_id;	/* offset of ssi0, ssi1, ssi2... */
25 	u32 offset_adr;	/* offset of SSICR, SSISR, ... */
26 };
27 
28 struct rsnd_gen {
29 	void __iomem *base[RSND_BASE_MAX];
30 
31 	struct rsnd_gen_reg_map reg_map[RSND_REG_MAX];
32 	struct rsnd_gen_ops *ops;
33 };
34 
35 #define rsnd_priv_to_gen(p)	((struct rsnd_gen *)(p)->gen)
36 
37 /*
38  *		Gen2
39  *		will be filled in the future
40  */
41 
42 /*
43  *		Gen1
44  */
45 static int rsnd_gen1_path_init(struct rsnd_priv *priv,
46 			       struct rsnd_dai *rdai,
47 			       struct rsnd_dai_stream *io)
48 {
49 	struct rsnd_mod *mod;
50 	int ret;
51 	int id;
52 
53 	/*
54 	 * Gen1 is created by SRU/SSI, and this SRU is base module of
55 	 * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU)
56 	 *
57 	 * Easy image is..
58 	 *	Gen1 SRU = Gen2 SCU + SSIU + etc
59 	 *
60 	 * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
61 	 * using fixed path.
62 	 *
63 	 * Then, SSI id = SCU id here
64 	 */
65 
66 	/* get SSI's ID */
67 	mod = rsnd_ssi_mod_get_frm_dai(priv,
68 				       rsnd_dai_id(priv, rdai),
69 				       rsnd_dai_is_play(rdai, io));
70 	id = rsnd_mod_id(mod);
71 
72 	/* SSI */
73 	mod = rsnd_ssi_mod_get(priv, id);
74 	ret = rsnd_dai_connect(rdai, mod, io);
75 	if (ret < 0)
76 		return ret;
77 
78 	/* SCU */
79 	mod = rsnd_scu_mod_get(priv, id);
80 	ret = rsnd_dai_connect(rdai, mod, io);
81 
82 	return ret;
83 }
84 
85 static int rsnd_gen1_path_exit(struct rsnd_priv *priv,
86 			       struct rsnd_dai *rdai,
87 			       struct rsnd_dai_stream *io)
88 {
89 	struct rsnd_mod *mod, *n;
90 	int ret = 0;
91 
92 	/*
93 	 * remove all mod from rdai
94 	 */
95 	for_each_rsnd_mod(mod, n, io)
96 		ret |= rsnd_dai_disconnect(mod);
97 
98 	return ret;
99 }
100 
101 static struct rsnd_gen_ops rsnd_gen1_ops = {
102 	.path_init	= rsnd_gen1_path_init,
103 	.path_exit	= rsnd_gen1_path_exit,
104 };
105 
106 #define RSND_GEN1_REG_MAP(g, s, i, oi, oa)				\
107 	do {								\
108 		(g)->reg_map[RSND_REG_##i].index  = RSND_GEN1_##s;	\
109 		(g)->reg_map[RSND_REG_##i].offset_id = oi;		\
110 		(g)->reg_map[RSND_REG_##i].offset_adr = oa;		\
111 	} while (0)
112 
113 static void rsnd_gen1_reg_map_init(struct rsnd_gen *gen)
114 {
115 	RSND_GEN1_REG_MAP(gen, SRU,	SRC_ROUTE_SEL,	0x0,	0x00);
116 	RSND_GEN1_REG_MAP(gen, SRU,	SRC_TMG_SEL0,	0x0,	0x08);
117 	RSND_GEN1_REG_MAP(gen, SRU,	SRC_TMG_SEL1,	0x0,	0x0c);
118 	RSND_GEN1_REG_MAP(gen, SRU,	SRC_TMG_SEL2,	0x0,	0x10);
119 	RSND_GEN1_REG_MAP(gen, SRU,	SRC_CTRL,	0x0,	0xc0);
120 	RSND_GEN1_REG_MAP(gen, SRU,	SSI_MODE0,	0x0,	0xD0);
121 	RSND_GEN1_REG_MAP(gen, SRU,	SSI_MODE1,	0x0,	0xD4);
122 	RSND_GEN1_REG_MAP(gen, SRU,	BUSIF_MODE,	0x4,	0x20);
123 	RSND_GEN1_REG_MAP(gen, SRU,	BUSIF_ADINR,	0x40,	0x214);
124 
125 	RSND_GEN1_REG_MAP(gen, ADG,	BRRA,		0x0,	0x00);
126 	RSND_GEN1_REG_MAP(gen, ADG,	BRRB,		0x0,	0x04);
127 	RSND_GEN1_REG_MAP(gen, ADG,	SSICKR,		0x0,	0x08);
128 	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL0,	0x0,	0x0c);
129 	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL1,	0x0,	0x10);
130 	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL3,	0x0,	0x18);
131 	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL4,	0x0,	0x1c);
132 	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL5,	0x0,	0x20);
133 
134 	RSND_GEN1_REG_MAP(gen, SSI,	SSICR,		0x40,	0x00);
135 	RSND_GEN1_REG_MAP(gen, SSI,	SSISR,		0x40,	0x04);
136 	RSND_GEN1_REG_MAP(gen, SSI,	SSITDR,		0x40,	0x08);
137 	RSND_GEN1_REG_MAP(gen, SSI,	SSIRDR,		0x40,	0x0c);
138 	RSND_GEN1_REG_MAP(gen, SSI,	SSIWSR,		0x40,	0x20);
139 }
140 
141 static int rsnd_gen1_probe(struct platform_device *pdev,
142 			   struct rcar_snd_info *info,
143 			   struct rsnd_priv *priv)
144 {
145 	struct device *dev = rsnd_priv_to_dev(priv);
146 	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
147 	struct resource *sru_res;
148 	struct resource *adg_res;
149 	struct resource *ssi_res;
150 
151 	/*
152 	 * map address
153 	 */
154 	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 	if (IS_ERR(gen->base[RSND_GEN1_SRU]) ||
162 	    IS_ERR(gen->base[RSND_GEN1_ADG]) ||
163 	    IS_ERR(gen->base[RSND_GEN1_SSI]))
164 		return -ENODEV;
165 
166 	gen->ops = &rsnd_gen1_ops;
167 	rsnd_gen1_reg_map_init(gen);
168 
169 	dev_dbg(dev, "Gen1 device probed\n");
170 	dev_dbg(dev, "SRU : %08x => %p\n",	sru_res->start,
171 						gen->base[RSND_GEN1_SRU]);
172 	dev_dbg(dev, "ADG : %08x => %p\n",	adg_res->start,
173 						gen->base[RSND_GEN1_ADG]);
174 	dev_dbg(dev, "SSI : %08x => %p\n",	ssi_res->start,
175 						gen->base[RSND_GEN1_SSI]);
176 
177 	return 0;
178 
179 }
180 
181 static void rsnd_gen1_remove(struct platform_device *pdev,
182 			     struct rsnd_priv *priv)
183 {
184 }
185 
186 /*
187  *		Gen
188  */
189 int rsnd_gen_path_init(struct rsnd_priv *priv,
190 		       struct rsnd_dai *rdai,
191 		       struct rsnd_dai_stream *io)
192 {
193 	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
194 
195 	return gen->ops->path_init(priv, rdai, io);
196 }
197 
198 int rsnd_gen_path_exit(struct rsnd_priv *priv,
199 		       struct rsnd_dai *rdai,
200 		       struct rsnd_dai_stream *io)
201 {
202 	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
203 
204 	return gen->ops->path_exit(priv, rdai, io);
205 }
206 
207 void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
208 			       struct rsnd_mod *mod,
209 			       enum rsnd_reg reg)
210 {
211 	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
212 	struct device *dev = rsnd_priv_to_dev(priv);
213 	int index;
214 	u32 offset_id, offset_adr;
215 
216 	if (reg >= RSND_REG_MAX) {
217 		dev_err(dev, "rsnd_reg reg error\n");
218 		return NULL;
219 	}
220 
221 	index		= gen->reg_map[reg].index;
222 	offset_id	= gen->reg_map[reg].offset_id;
223 	offset_adr	= gen->reg_map[reg].offset_adr;
224 
225 	if (index < 0) {
226 		dev_err(dev, "unsupported reg access %d\n", reg);
227 		return NULL;
228 	}
229 
230 	if (offset_id && mod)
231 		offset_id *= rsnd_mod_id(mod);
232 
233 	/*
234 	 * index/offset were set on gen1/gen2
235 	 */
236 
237 	return gen->base[index] + offset_id + offset_adr;
238 }
239 
240 int rsnd_gen_probe(struct platform_device *pdev,
241 		   struct rcar_snd_info *info,
242 		   struct rsnd_priv *priv)
243 {
244 	struct device *dev = rsnd_priv_to_dev(priv);
245 	struct rsnd_gen *gen;
246 	int i;
247 
248 	gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
249 	if (!gen) {
250 		dev_err(dev, "GEN allocate failed\n");
251 		return -ENOMEM;
252 	}
253 
254 	priv->gen = gen;
255 
256 	/*
257 	 * see
258 	 *	rsnd_reg_get()
259 	 *	rsnd_gen_probe()
260 	 */
261 	for (i = 0; i < RSND_REG_MAX; i++)
262 		gen->reg_map[i].index = -1;
263 
264 	/*
265 	 *	init each module
266 	 */
267 	if (rsnd_is_gen1(priv))
268 		return rsnd_gen1_probe(pdev, info, priv);
269 
270 	dev_err(dev, "unknown generation R-Car sound device\n");
271 
272 	return -ENODEV;
273 }
274 
275 void rsnd_gen_remove(struct platform_device *pdev,
276 		     struct rsnd_priv *priv)
277 {
278 	if (rsnd_is_gen1(priv))
279 		rsnd_gen1_remove(pdev, priv);
280 }
281