aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2016-03-07 00:09:14 -0500
committerMark Brown <broonie@kernel.org>2016-03-07 02:41:54 -0500
commit0102eed57c47371023c03b3b0c564f33d5e94570 (patch)
treec8c20d2ae4dfda733c23003ea1d3c1d2d7732d6c
parentcbf1494fbcc80d363477af1efefb2380e7660a24 (diff)
ASoC: rsnd: SRC TIMSEL support for Capture
SRC has Sync/Async mode, and it can't use Sync mode when Capture with CMD. In Async mode, it needs to care about in/out SRC rate for settings, but current driver supporting Playback case only. This patch supports Capture case. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/sh/rcar/adg.c204
-rw-r--r--sound/soc/sh/rcar/rsnd.h8
-rw-r--r--sound/soc/sh/rcar/src.c26
3 files changed, 128 insertions, 110 deletions
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index d74e1ccc0f8f..f7e164c89f33 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -90,6 +90,108 @@ static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
90 return (0x6 + ws) << 8; 90 return (0x6 + ws) << 8;
91} 91}
92 92
93static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
94 struct rsnd_dai_stream *io,
95 unsigned int target_rate,
96 unsigned int *target_val,
97 unsigned int *target_en)
98{
99 struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
100 struct device *dev = rsnd_priv_to_dev(priv);
101 int idx, sel, div, step;
102 unsigned int val, en;
103 unsigned int min, diff;
104 unsigned int sel_rate[] = {
105 clk_get_rate(adg->clk[CLKA]), /* 0000: CLKA */
106 clk_get_rate(adg->clk[CLKB]), /* 0001: CLKB */
107 clk_get_rate(adg->clk[CLKC]), /* 0010: CLKC */
108 adg->rbga_rate_for_441khz, /* 0011: RBGA */
109 adg->rbgb_rate_for_48khz, /* 0100: RBGB */
110 };
111
112 min = ~0;
113 val = 0;
114 en = 0;
115 for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
116 idx = 0;
117 step = 2;
118
119 if (!sel_rate[sel])
120 continue;
121
122 for (div = 2; div <= 98304; div += step) {
123 diff = abs(target_rate - sel_rate[sel] / div);
124 if (min > diff) {
125 val = (sel << 8) | idx;
126 min = diff;
127 en = 1 << (sel + 1); /* fixme */
128 }
129
130 /*
131 * step of 0_0000 / 0_0001 / 0_1101
132 * are out of order
133 */
134 if ((idx > 2) && (idx % 2))
135 step *= 2;
136 if (idx == 0x1c) {
137 div += step;
138 step *= 2;
139 }
140 idx++;
141 }
142 }
143
144 if (min == ~0) {
145 dev_err(dev, "no Input clock\n");
146 return;
147 }
148
149 *target_val = val;
150 if (target_en)
151 *target_en = en;
152}
153
154static void rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
155 struct rsnd_dai_stream *io,
156 unsigned int in_rate,
157 unsigned int out_rate,
158 u32 *in, u32 *out, u32 *en)
159{
160 struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
161 unsigned int target_rate;
162 u32 *target_val;
163 u32 _in;
164 u32 _out;
165 u32 _en;
166
167 /* default = SSI WS */
168 _in =
169 _out = rsnd_adg_ssi_ws_timing_gen2(io);
170
171 target_rate = 0;
172 target_val = NULL;
173 _en = 0;
174 if (runtime->rate != in_rate) {
175 target_rate = out_rate;
176 target_val = &_out;
177 } else if (runtime->rate != out_rate) {
178 target_rate = in_rate;
179 target_val = &_in;
180 }
181
182 if (target_rate)
183 __rsnd_adg_get_timesel_ratio(priv, io,
184 target_rate,
185 target_val, &_en);
186
187 if (in)
188 *in = _in;
189 if (out)
190 *out = _out;
191 if (en)
192 *en = _en;
193}
194
93int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, 195int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
94 struct rsnd_dai_stream *io) 196 struct rsnd_dai_stream *io)
95{ 197{
@@ -110,25 +212,24 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
110 return 0; 212 return 0;
111} 213}
112 214
113static int rsnd_adg_set_src_timsel_gen2(struct rsnd_mod *src_mod, 215int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
114 struct rsnd_dai_stream *io, 216 struct rsnd_dai_stream *io,
115 u32 timsel) 217 unsigned int in_rate,
218 unsigned int out_rate)
116{ 219{
117 struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod); 220 struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod);
118 struct rsnd_adg *adg = rsnd_priv_to_adg(priv); 221 struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
119 struct rsnd_mod *adg_mod = rsnd_mod_get(adg); 222 struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
120 int is_play = rsnd_io_is_play(io); 223 u32 in, out;
224 u32 mask, en;
121 int id = rsnd_mod_id(src_mod); 225 int id = rsnd_mod_id(src_mod);
122 int shift = (id % 2) ? 16 : 0; 226 int shift = (id % 2) ? 16 : 0;
123 u32 mask, ws;
124 u32 in, out;
125 227
126 rsnd_mod_confirm_src(src_mod); 228 rsnd_mod_confirm_src(src_mod);
127 229
128 ws = rsnd_adg_ssi_ws_timing_gen2(io); 230 rsnd_adg_get_timesel_ratio(priv, io,
129 231 in_rate, out_rate,
130 in = (is_play) ? timsel : ws; 232 &in, &out, &en);
131 out = (is_play) ? ws : timsel;
132 233
133 in = in << shift; 234 in = in << shift;
134 out = out << shift; 235 out = out << shift;
@@ -157,91 +258,12 @@ static int rsnd_adg_set_src_timsel_gen2(struct rsnd_mod *src_mod,
157 break; 258 break;
158 } 259 }
159 260
160 return 0; 261 if (en)
161} 262 rsnd_mod_bset(adg_mod, DIV_EN, en, en);
162
163int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *src_mod,
164 struct rsnd_dai_stream *io,
165 unsigned int src_rate,
166 unsigned int dst_rate)
167{
168 struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod);
169 struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
170 struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
171 struct device *dev = rsnd_priv_to_dev(priv);
172 int idx, sel, div, step, ret;
173 u32 val, en;
174 unsigned int min, diff;
175 unsigned int sel_rate [] = {
176 clk_get_rate(adg->clk[CLKA]), /* 0000: CLKA */
177 clk_get_rate(adg->clk[CLKB]), /* 0001: CLKB */
178 clk_get_rate(adg->clk[CLKC]), /* 0010: CLKC */
179 adg->rbga_rate_for_441khz, /* 0011: RBGA */
180 adg->rbgb_rate_for_48khz, /* 0100: RBGB */
181 };
182
183 rsnd_mod_confirm_src(src_mod);
184
185 min = ~0;
186 val = 0;
187 en = 0;
188 for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
189 idx = 0;
190 step = 2;
191
192 if (!sel_rate[sel])
193 continue;
194
195 for (div = 2; div <= 98304; div += step) {
196 diff = abs(src_rate - sel_rate[sel] / div);
197 if (min > diff) {
198 val = (sel << 8) | idx;
199 min = diff;
200 en = 1 << (sel + 1); /* fixme */
201 }
202
203 /*
204 * step of 0_0000 / 0_0001 / 0_1101
205 * are out of order
206 */
207 if ((idx > 2) && (idx % 2))
208 step *= 2;
209 if (idx == 0x1c) {
210 div += step;
211 step *= 2;
212 }
213 idx++;
214 }
215 }
216
217 if (min == ~0) {
218 dev_err(dev, "no Input clock\n");
219 return -EIO;
220 }
221
222 ret = rsnd_adg_set_src_timsel_gen2(src_mod, io, val);
223 if (ret < 0) {
224 dev_err(dev, "timsel error\n");
225 return ret;
226 }
227
228 rsnd_mod_bset(adg_mod, DIV_EN, en, en);
229
230 dev_dbg(dev, "convert rate %d <-> %d\n", src_rate, dst_rate);
231 263
232 return 0; 264 return 0;
233} 265}
234 266
235int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *src_mod,
236 struct rsnd_dai_stream *io)
237{
238 u32 val = rsnd_adg_ssi_ws_timing_gen2(io);
239
240 rsnd_mod_confirm_src(src_mod);
241
242 return rsnd_adg_set_src_timsel_gen2(src_mod, io, val);
243}
244
245static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) 267static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
246{ 268{
247 struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); 269 struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 4b77f33358fb..fc89a67258ca 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -446,12 +446,10 @@ int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod);
446int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); 446int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate);
447int rsnd_adg_probe(struct rsnd_priv *priv); 447int rsnd_adg_probe(struct rsnd_priv *priv);
448void rsnd_adg_remove(struct rsnd_priv *priv); 448void rsnd_adg_remove(struct rsnd_priv *priv);
449int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod, 449int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
450 struct rsnd_dai_stream *io, 450 struct rsnd_dai_stream *io,
451 unsigned int src_rate, 451 unsigned int in_rate,
452 unsigned int dst_rate); 452 unsigned int out_rate);
453int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod,
454 struct rsnd_dai_stream *io);
455int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod, 453int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
456 struct rsnd_dai_stream *io); 454 struct rsnd_dai_stream *io);
457 455
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index d1a8741cc446..15d6ffe8be74 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -189,7 +189,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
189 struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 189 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
190 struct device *dev = rsnd_priv_to_dev(priv); 190 struct device *dev = rsnd_priv_to_dev(priv);
191 struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); 191 struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
192 u32 convert_rate = rsnd_src_convert_rate(io, mod); 192 u32 fin, fout;
193 u32 ifscr, fsrate, adinr; 193 u32 ifscr, fsrate, adinr;
194 u32 cr, route; 194 u32 cr, route;
195 u32 bsdsr, bsisr; 195 u32 bsdsr, bsisr;
@@ -198,13 +198,16 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
198 if (!runtime) 198 if (!runtime)
199 return; 199 return;
200 200
201 fin = rsnd_src_get_in_rate(priv, io);
202 fout = rsnd_src_get_out_rate(priv, io);
203
201 /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ 204 /* 6 - 1/6 are very enough ratio for SRC_BSDSR */
202 if (!convert_rate) 205 if (fin == fout)
203 ratio = 0; 206 ratio = 0;
204 else if (convert_rate > runtime->rate) 207 else if (fin > fout)
205 ratio = 100 * convert_rate / runtime->rate; 208 ratio = 100 * fin / fout;
206 else 209 else
207 ratio = 100 * runtime->rate / convert_rate; 210 ratio = 100 * fout / fin;
208 211
209 if (ratio > 600) { 212 if (ratio > 600) {
210 dev_err(dev, "FSO/FSI ratio error\n"); 213 dev_err(dev, "FSO/FSI ratio error\n");
@@ -222,9 +225,9 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
222 */ 225 */
223 ifscr = 0; 226 ifscr = 0;
224 fsrate = 0; 227 fsrate = 0;
225 if (convert_rate) { 228 if (fin != fout) {
226 ifscr = 1; 229 ifscr = 1;
227 fsrate = 0x0400000 / convert_rate * runtime->rate; 230 fsrate = 0x0400000 / fout * fin;
228 } 231 }
229 232
230 /* 233 /*
@@ -232,7 +235,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
232 */ 235 */
233 cr = 0x00011110; 236 cr = 0x00011110;
234 route = 0x0; 237 route = 0x0;
235 if (convert_rate) { 238 if (fin != fout) {
236 route = 0x1; 239 route = 0x1;
237 240
238 if (rsnd_src_sync_is_enabled(mod)) { 241 if (rsnd_src_sync_is_enabled(mod)) {
@@ -274,12 +277,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
274 rsnd_mod_write(mod, SRC_O_BUSIF_MODE, 1); 277 rsnd_mod_write(mod, SRC_O_BUSIF_MODE, 1);
275 rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); 278 rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io));
276 279
277 if (convert_rate) 280 rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout);
278 rsnd_adg_set_convert_clk_gen2(mod, io,
279 runtime->rate,
280 convert_rate);
281 else
282 rsnd_adg_set_convert_timing_gen2(mod, io);
283} 281}
284 282
285static int rsnd_src_irq(struct rsnd_mod *mod, 283static int rsnd_src_irq(struct rsnd_mod *mod,