ASoC: rsnd: route setting is needed only Gen1
[deliverable/linux.git] / sound / soc / sh / rcar / scu.c
CommitLineData
07539c1d
KM
1/*
2 * Renesas R-Car SCU 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
13struct rsnd_scu {
14 struct rsnd_scu_platform_info *info; /* rcar_snd.h */
15 struct rsnd_mod mod;
16};
17
374a5281
KM
18#define rsnd_scu_mode_flags(p) ((p)->info->flags)
19
20/*
21 * ADINR
22 */
23#define OTBL_24 (0 << 16)
24#define OTBL_22 (2 << 16)
25#define OTBL_20 (4 << 16)
26#define OTBL_18 (6 << 16)
27#define OTBL_16 (8 << 16)
28
29
07539c1d
KM
30#define rsnd_mod_to_scu(_mod) \
31 container_of((_mod), struct rsnd_scu, mod)
32
33#define for_each_rsnd_scu(pos, priv, i) \
34 for ((i) = 0; \
35 ((i) < rsnd_scu_nr(priv)) && \
36 ((pos) = (struct rsnd_scu *)(priv)->scu + i); \
37 i++)
38
2582718c
KM
39/* Gen1 only */
40static int rsnd_src_set_route_if_gen1(struct rsnd_priv *priv,
374a5281
KM
41 struct rsnd_mod *mod,
42 struct rsnd_dai *rdai,
43 struct rsnd_dai_stream *io)
44{
45 struct scu_route_config {
46 u32 mask;
47 int shift;
48 } routes[] = {
49 { 0xF, 0, }, /* 0 */
50 { 0xF, 4, }, /* 1 */
51 { 0xF, 8, }, /* 2 */
52 { 0x7, 12, }, /* 3 */
53 { 0x7, 16, }, /* 4 */
54 { 0x7, 20, }, /* 5 */
55 { 0x7, 24, }, /* 6 */
56 { 0x3, 28, }, /* 7 */
57 { 0x3, 30, }, /* 8 */
58 };
59
60 u32 mask;
61 u32 val;
62 int shift;
63 int id;
64
65 /*
66 * Gen1 only
67 */
68 if (!rsnd_is_gen1(priv))
69 return 0;
70
71 id = rsnd_mod_id(mod);
72 if (id < 0 || id > ARRAY_SIZE(routes))
73 return -EIO;
74
75 /*
76 * SRC_ROUTE_SELECT
77 */
78 val = rsnd_dai_is_play(rdai, io) ? 0x1 : 0x2;
79 val = val << routes[id].shift;
80 mask = routes[id].mask << routes[id].shift;
81
82 rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val);
83
84 /*
85 * SRC_TIMING_SELECT
86 */
87 shift = (id % 4) * 8;
88 mask = 0x1F << shift;
89 if (8 == id) /* SRU8 is very special */
90 val = id << shift;
91 else
92 val = (id + 1) << shift;
93
94 switch (id / 4) {
95 case 0:
96 rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val);
97 break;
98 case 1:
99 rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val);
100 break;
101 case 2:
102 rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val);
103 break;
104 }
105
106 return 0;
107}
108
109static int rsnd_scu_set_mode(struct rsnd_priv *priv,
110 struct rsnd_mod *mod,
111 struct rsnd_dai *rdai,
112 struct rsnd_dai_stream *io)
113{
114 int id = rsnd_mod_id(mod);
115 u32 val;
116
117 if (rsnd_is_gen1(priv)) {
118 val = (1 << id);
690ef81e 119 rsnd_mod_bset(mod, SRC_ROUTE_CTRL, val, val);
374a5281
KM
120 }
121
122 return 0;
123}
124
125static int rsnd_scu_set_hpbif(struct rsnd_priv *priv,
126 struct rsnd_mod *mod,
127 struct rsnd_dai *rdai,
128 struct rsnd_dai_stream *io)
129{
130 struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
131 u32 adinr = runtime->channels;
132
133 switch (runtime->sample_bits) {
134 case 16:
135 adinr |= OTBL_16;
136 break;
137 case 32:
138 adinr |= OTBL_24;
139 break;
140 default:
141 return -EIO;
142 }
143
144 rsnd_mod_write(mod, BUSIF_MODE, 1);
690ef81e 145 rsnd_mod_write(mod, SRC_ADINR, adinr);
374a5281
KM
146
147 return 0;
148}
149
cdcfcac9
KM
150bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod)
151{
152 struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
153 u32 flags = rsnd_scu_mode_flags(scu);
154
155 return !!(flags & RSND_SCU_USE_HPBIF);
156}
157
07539c1d
KM
158static int rsnd_scu_start(struct rsnd_mod *mod,
159 struct rsnd_dai *rdai,
160 struct rsnd_dai_stream *io)
161{
162 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
163 struct device *dev = rsnd_priv_to_dev(priv);
374a5281
KM
164 int ret;
165
166 /*
34e44475 167 * SCU will be used if it has RSND_SCU_USE_HPBIF flags
374a5281 168 */
cdcfcac9 169 if (!rsnd_scu_hpbif_is_enable(mod)) {
374a5281
KM
170 /* it use PIO transter */
171 dev_dbg(dev, "%s%d is not used\n",
172 rsnd_mod_name(mod), rsnd_mod_id(mod));
173
174 return 0;
175 }
176
177 /* it use DMA transter */
2582718c
KM
178
179 ret = rsnd_src_set_route_if_gen1(priv, mod, rdai, io);
374a5281
KM
180 if (ret < 0)
181 return ret;
182
183 ret = rsnd_scu_set_mode(priv, mod, rdai, io);
184 if (ret < 0)
185 return ret;
07539c1d 186
374a5281
KM
187 ret = rsnd_scu_set_hpbif(priv, mod, rdai, io);
188 if (ret < 0)
189 return ret;
190
191 dev_dbg(dev, "%s%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
07539c1d
KM
192
193 return 0;
194}
195
07539c1d
KM
196static struct rsnd_mod_ops rsnd_scu_ops = {
197 .name = "scu",
07539c1d 198 .start = rsnd_scu_start,
07539c1d
KM
199};
200
201struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id)
202{
203 BUG_ON(id < 0 || id >= rsnd_scu_nr(priv));
204
205 return &((struct rsnd_scu *)(priv->scu) + id)->mod;
206}
207
208int rsnd_scu_probe(struct platform_device *pdev,
209 struct rcar_snd_info *info,
210 struct rsnd_priv *priv)
211{
212 struct device *dev = rsnd_priv_to_dev(priv);
213 struct rsnd_scu *scu;
214 int i, nr;
215
216 /*
217 * init SCU
218 */
219 nr = info->scu_info_nr;
220 scu = devm_kzalloc(dev, sizeof(*scu) * nr, GFP_KERNEL);
221 if (!scu) {
222 dev_err(dev, "SCU allocate failed\n");
223 return -ENOMEM;
224 }
225
226 priv->scu_nr = nr;
227 priv->scu = scu;
228
229 for_each_rsnd_scu(scu, priv, i) {
230 rsnd_mod_init(priv, &scu->mod,
231 &rsnd_scu_ops, i);
232 scu->info = &info->scu_info[i];
07539c1d 233
374a5281
KM
234 dev_dbg(dev, "SCU%d probed\n", i);
235 }
07539c1d
KM
236 dev_dbg(dev, "scu probed\n");
237
238 return 0;
239}
240
241void rsnd_scu_remove(struct platform_device *pdev,
242 struct rsnd_priv *priv)
243{
244}
This page took 0.045827 seconds and 5 git commands to generate.