aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/sh/rcar/scu.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sh/rcar/scu.c')
-rw-r--r--sound/soc/sh/rcar/scu.c181
1 files changed, 161 insertions, 20 deletions
diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c
index fa8fa15860b9..9bb08bb1d455 100644
--- a/sound/soc/sh/rcar/scu.c
+++ b/sound/soc/sh/rcar/scu.c
@@ -13,9 +13,13 @@
13struct rsnd_scu { 13struct rsnd_scu {
14 struct rsnd_scu_platform_info *info; /* rcar_snd.h */ 14 struct rsnd_scu_platform_info *info; /* rcar_snd.h */
15 struct rsnd_mod mod; 15 struct rsnd_mod mod;
16 struct clk *clk;
16}; 17};
17 18
18#define rsnd_scu_mode_flags(p) ((p)->info->flags) 19#define rsnd_scu_mode_flags(p) ((p)->info->flags)
20#define rsnd_scu_convert_rate(p) ((p)->info->convert_rate)
21
22#define RSND_SCU_NAME_SIZE 16
19 23
20/* 24/*
21 * ADINR 25 * ADINR
@@ -26,6 +30,15 @@ struct rsnd_scu {
26#define OTBL_18 (6 << 16) 30#define OTBL_18 (6 << 16)
27#define OTBL_16 (8 << 16) 31#define OTBL_16 (8 << 16)
28 32
33/*
34 * image of SRC (Sampling Rate Converter)
35 *
36 * 96kHz <-> +-----+ 48kHz +-----+ 48kHz +-------+
37 * 48kHz <-> | SRC | <------> | SSI | <-----> | codec |
38 * 44.1kHz <-> +-----+ +-----+ +-------+
39 * ...
40 *
41 */
29 42
30#define rsnd_mod_to_scu(_mod) \ 43#define rsnd_mod_to_scu(_mod) \
31 container_of((_mod), struct rsnd_scu, mod) 44 container_of((_mod), struct rsnd_scu, mod)
@@ -36,7 +49,8 @@ struct rsnd_scu {
36 ((pos) = (struct rsnd_scu *)(priv)->scu + i); \ 49 ((pos) = (struct rsnd_scu *)(priv)->scu + i); \
37 i++) 50 i++)
38 51
39static int rsnd_scu_set_route(struct rsnd_priv *priv, 52/* Gen1 only */
53static int rsnd_src_set_route_if_gen1(struct rsnd_priv *priv,
40 struct rsnd_mod *mod, 54 struct rsnd_mod *mod,
41 struct rsnd_dai *rdai, 55 struct rsnd_dai *rdai,
42 struct rsnd_dai_stream *io) 56 struct rsnd_dai_stream *io)
@@ -55,7 +69,7 @@ static int rsnd_scu_set_route(struct rsnd_priv *priv,
55 { 0x3, 28, }, /* 7 */ 69 { 0x3, 28, }, /* 7 */
56 { 0x3, 30, }, /* 8 */ 70 { 0x3, 30, }, /* 8 */
57 }; 71 };
58 72 struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
59 u32 mask; 73 u32 mask;
60 u32 val; 74 u32 val;
61 int shift; 75 int shift;
@@ -85,9 +99,18 @@ static int rsnd_scu_set_route(struct rsnd_priv *priv,
85 */ 99 */
86 shift = (id % 4) * 8; 100 shift = (id % 4) * 8;
87 mask = 0x1F << shift; 101 mask = 0x1F << shift;
88 if (8 == id) /* SRU8 is very special */ 102
103 /*
104 * ADG is used as source clock if SRC was used,
105 * then, SSI WS is used as destination clock.
106 * SSI WS is used as source clock if SRC is not used
107 * (when playback, source/destination become reverse when capture)
108 */
109 if (rsnd_scu_convert_rate(scu)) /* use ADG */
110 val = 0;
111 else if (8 == id) /* use SSI WS, but SRU8 is special */
89 val = id << shift; 112 val = id << shift;
90 else 113 else /* use SSI WS */
91 val = (id + 1) << shift; 114 val = (id + 1) << shift;
92 115
93 switch (id / 4) { 116 switch (id / 4) {
@@ -105,30 +128,45 @@ static int rsnd_scu_set_route(struct rsnd_priv *priv,
105 return 0; 128 return 0;
106} 129}
107 130
108static int rsnd_scu_set_mode(struct rsnd_priv *priv, 131unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv,
109 struct rsnd_mod *mod, 132 struct rsnd_mod *ssi_mod,
110 struct rsnd_dai *rdai, 133 struct snd_pcm_runtime *runtime)
111 struct rsnd_dai_stream *io)
112{ 134{
113 int id = rsnd_mod_id(mod); 135 struct rsnd_scu *scu;
114 u32 val; 136 unsigned int rate;
115 137
116 if (rsnd_is_gen1(priv)) { 138 /* this function is assuming SSI id = SCU id here */
117 val = (1 << id); 139 scu = rsnd_mod_to_scu(rsnd_scu_mod_get(priv, rsnd_mod_id(ssi_mod)));
118 rsnd_mod_bset(mod, SRC_CTRL, val, val);
119 }
120 140
121 return 0; 141 /*
142 * return convert rate if SRC is used,
143 * otherwise, return runtime->rate as usual
144 */
145 rate = rsnd_scu_convert_rate(scu);
146 if (!rate)
147 rate = runtime->rate;
148
149 return rate;
122} 150}
123 151
124static int rsnd_scu_set_hpbif(struct rsnd_priv *priv, 152static int rsnd_scu_convert_rate_ctrl(struct rsnd_priv *priv,
125 struct rsnd_mod *mod, 153 struct rsnd_mod *mod,
126 struct rsnd_dai *rdai, 154 struct rsnd_dai *rdai,
127 struct rsnd_dai_stream *io) 155 struct rsnd_dai_stream *io)
128{ 156{
129 struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); 157 struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
158 struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
159 u32 convert_rate = rsnd_scu_convert_rate(scu);
130 u32 adinr = runtime->channels; 160 u32 adinr = runtime->channels;
131 161
162 /* set/clear soft reset */
163 rsnd_mod_write(mod, SRC_SWRSR, 0);
164 rsnd_mod_write(mod, SRC_SWRSR, 1);
165
166 /* Initialize the operation of the SRC internal circuits */
167 rsnd_mod_write(mod, SRC_SRCIR, 1);
168
169 /* Set channel number and output bit length */
132 switch (runtime->sample_bits) { 170 switch (runtime->sample_bits) {
133 case 16: 171 case 16:
134 adinr |= OTBL_16; 172 adinr |= OTBL_16;
@@ -139,9 +177,81 @@ static int rsnd_scu_set_hpbif(struct rsnd_priv *priv,
139 default: 177 default:
140 return -EIO; 178 return -EIO;
141 } 179 }
180 rsnd_mod_write(mod, SRC_ADINR, adinr);
181
182 if (convert_rate) {
183 u32 fsrate = 0x0400000 / convert_rate * runtime->rate;
184 int ret;
185
186 /* Enable the initial value of IFS */
187 rsnd_mod_write(mod, SRC_IFSCR, 1);
188
189 /* Set initial value of IFS */
190 rsnd_mod_write(mod, SRC_IFSVR, fsrate);
191
192 /* Select SRC mode (fixed value) */
193 rsnd_mod_write(mod, SRC_SRCCR, 0x00010110);
194
195 /* Set the restriction value of the FS ratio (98%) */
196 rsnd_mod_write(mod, SRC_MNFSR, fsrate / 100 * 98);
197
198 if (rsnd_is_gen1(priv)) {
199 /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */
200 }
142 201
202 /* set convert clock */
203 ret = rsnd_adg_set_convert_clk(priv, mod,
204 runtime->rate,
205 convert_rate);
206 if (ret < 0)
207 return ret;
208 }
209
210 /* Cancel the initialization and operate the SRC function */
211 rsnd_mod_write(mod, SRC_SRCIR, 0);
212
213 /* use DMA transfer */
143 rsnd_mod_write(mod, BUSIF_MODE, 1); 214 rsnd_mod_write(mod, BUSIF_MODE, 1);
144 rsnd_mod_write(mod, BUSIF_ADINR, adinr); 215
216 return 0;
217}
218
219static int rsnd_scu_transfer_start(struct rsnd_priv *priv,
220 struct rsnd_mod *mod,
221 struct rsnd_dai *rdai,
222 struct rsnd_dai_stream *io)
223{
224 struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
225 int id = rsnd_mod_id(mod);
226 u32 val;
227
228 if (rsnd_is_gen1(priv)) {
229 val = (1 << id);
230 rsnd_mod_bset(mod, SRC_ROUTE_CTRL, val, val);
231 }
232
233 if (rsnd_scu_convert_rate(scu))
234 rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
235
236 return 0;
237}
238
239static int rsnd_scu_transfer_stop(struct rsnd_priv *priv,
240 struct rsnd_mod *mod,
241 struct rsnd_dai *rdai,
242 struct rsnd_dai_stream *io)
243{
244 struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
245 int id = rsnd_mod_id(mod);
246 u32 mask;
247
248 if (rsnd_is_gen1(priv)) {
249 mask = (1 << id);
250 rsnd_mod_bset(mod, SRC_ROUTE_CTRL, mask, 0);
251 }
252
253 if (rsnd_scu_convert_rate(scu))
254 rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0);
145 255
146 return 0; 256 return 0;
147} 257}
@@ -159,6 +269,7 @@ static int rsnd_scu_start(struct rsnd_mod *mod,
159 struct rsnd_dai_stream *io) 269 struct rsnd_dai_stream *io)
160{ 270{
161 struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 271 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
272 struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
162 struct device *dev = rsnd_priv_to_dev(priv); 273 struct device *dev = rsnd_priv_to_dev(priv);
163 int ret; 274 int ret;
164 275
@@ -173,16 +284,19 @@ static int rsnd_scu_start(struct rsnd_mod *mod,
173 return 0; 284 return 0;
174 } 285 }
175 286
287 clk_enable(scu->clk);
288
176 /* it use DMA transter */ 289 /* it use DMA transter */
177 ret = rsnd_scu_set_route(priv, mod, rdai, io); 290
291 ret = rsnd_src_set_route_if_gen1(priv, mod, rdai, io);
178 if (ret < 0) 292 if (ret < 0)
179 return ret; 293 return ret;
180 294
181 ret = rsnd_scu_set_mode(priv, mod, rdai, io); 295 ret = rsnd_scu_convert_rate_ctrl(priv, mod, rdai, io);
182 if (ret < 0) 296 if (ret < 0)
183 return ret; 297 return ret;
184 298
185 ret = rsnd_scu_set_hpbif(priv, mod, rdai, io); 299 ret = rsnd_scu_transfer_start(priv, mod, rdai, io);
186 if (ret < 0) 300 if (ret < 0)
187 return ret; 301 return ret;
188 302
@@ -191,9 +305,27 @@ static int rsnd_scu_start(struct rsnd_mod *mod,
191 return 0; 305 return 0;
192} 306}
193 307
308static int rsnd_scu_stop(struct rsnd_mod *mod,
309 struct rsnd_dai *rdai,
310 struct rsnd_dai_stream *io)
311{
312 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
313 struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
314
315 if (!rsnd_scu_hpbif_is_enable(mod))
316 return 0;
317
318 rsnd_scu_transfer_stop(priv, mod, rdai, io);
319
320 clk_disable(scu->clk);
321
322 return 0;
323}
324
194static struct rsnd_mod_ops rsnd_scu_ops = { 325static struct rsnd_mod_ops rsnd_scu_ops = {
195 .name = "scu", 326 .name = "scu",
196 .start = rsnd_scu_start, 327 .start = rsnd_scu_start,
328 .stop = rsnd_scu_stop,
197}; 329};
198 330
199struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id) 331struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id)
@@ -210,6 +342,8 @@ int rsnd_scu_probe(struct platform_device *pdev,
210{ 342{
211 struct device *dev = rsnd_priv_to_dev(priv); 343 struct device *dev = rsnd_priv_to_dev(priv);
212 struct rsnd_scu *scu; 344 struct rsnd_scu *scu;
345 struct clk *clk;
346 char name[RSND_SCU_NAME_SIZE];
213 int i, nr; 347 int i, nr;
214 348
215 /* 349 /*
@@ -226,9 +360,16 @@ int rsnd_scu_probe(struct platform_device *pdev,
226 priv->scu = scu; 360 priv->scu = scu;
227 361
228 for_each_rsnd_scu(scu, priv, i) { 362 for_each_rsnd_scu(scu, priv, i) {
363 snprintf(name, RSND_SCU_NAME_SIZE, "scu.%d", i);
364
365 clk = devm_clk_get(dev, name);
366 if (IS_ERR(clk))
367 return PTR_ERR(clk);
368
229 rsnd_mod_init(priv, &scu->mod, 369 rsnd_mod_init(priv, &scu->mod,
230 &rsnd_scu_ops, i); 370 &rsnd_scu_ops, i);
231 scu->info = &info->scu_info[i]; 371 scu->info = &info->scu_info[i];
372 scu->clk = clk;
232 373
233 dev_dbg(dev, "SCU%d probed\n", i); 374 dev_dbg(dev, "SCU%d probed\n", i);
234 } 375 }