]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - sound/soc/sh/rcar/dvc.c
Merge remote-tracking branch 'asoc/topic/simple' into asoc-next
[mirror_ubuntu-artful-kernel.git] / sound / soc / sh / rcar / dvc.c
CommitLineData
bff58ea4
KM
1/*
2 * Renesas R-Car DVC support
3 *
4 * Copyright (C) 2014 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#define RSND_DVC_NAME_SIZE 16
8aefda50
KM
14
15#define DVC_NAME "dvc"
16
bff58ea4
KM
17struct rsnd_dvc {
18 struct rsnd_dvc_platform_info *info; /* rcar_snd.h */
19 struct rsnd_mod mod;
170a2497
KM
20 struct rsnd_kctrl_cfg_m volume;
21 struct rsnd_kctrl_cfg_m mute;
22 struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */
23 struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */
24 struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */
bff58ea4
KM
25};
26
93b986e2
KM
27#define rsnd_dvc_of_node(priv) \
28 of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
29
bff58ea4
KM
30#define rsnd_mod_to_dvc(_mod) \
31 container_of((_mod), struct rsnd_dvc, mod)
32
33#define for_each_rsnd_dvc(pos, priv, i) \
34 for ((i) = 0; \
35 ((i) < rsnd_dvc_nr(priv)) && \
36 ((pos) = (struct rsnd_dvc *)(priv)->dvc + i); \
37 i++)
38
2f4b1e6b 39static const char * const dvc_ramp_rate[] = {
3539cacf
KM
40 "128 dB/1 step", /* 00000 */
41 "64 dB/1 step", /* 00001 */
42 "32 dB/1 step", /* 00010 */
43 "16 dB/1 step", /* 00011 */
44 "8 dB/1 step", /* 00100 */
45 "4 dB/1 step", /* 00101 */
46 "2 dB/1 step", /* 00110 */
47 "1 dB/1 step", /* 00111 */
48 "0.5 dB/1 step", /* 01000 */
49 "0.25 dB/1 step", /* 01001 */
50 "0.125 dB/1 step", /* 01010 */
51 "0.125 dB/2 steps", /* 01011 */
52 "0.125 dB/4 steps", /* 01100 */
53 "0.125 dB/8 steps", /* 01101 */
54 "0.125 dB/16 steps", /* 01110 */
55 "0.125 dB/32 steps", /* 01111 */
56 "0.125 dB/64 steps", /* 10000 */
57 "0.125 dB/128 steps", /* 10001 */
58 "0.125 dB/256 steps", /* 10010 */
59 "0.125 dB/512 steps", /* 10011 */
60 "0.125 dB/1024 steps", /* 10100 */
61 "0.125 dB/2048 steps", /* 10101 */
62 "0.125 dB/4096 steps", /* 10110 */
63 "0.125 dB/8192 steps", /* 10111 */
64};
65
b65a7ccc
KM
66static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
67 struct rsnd_mod *mod)
bff58ea4
KM
68{
69 struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
3539cacf 70 u32 val[RSND_DVC_CHANNELS];
1c5d1c98 71 u32 dvucr = 0;
cd2b6574 72 u32 mute = 0;
bff58ea4
KM
73 int i;
74
ec14af91
KM
75 for (i = 0; i < dvc->mute.cfg.size; i++)
76 mute |= (!!dvc->mute.cfg.val[i]) << i;
bff58ea4 77
140bab89
KM
78 /* Disable DVC Register access */
79 rsnd_mod_write(mod, DVC_DVUER, 0);
80
3539cacf
KM
81 /* Enable Ramp */
82 if (dvc->ren.val) {
83 dvucr |= 0x10;
84
85 /* Digital Volume Max */
86 for (i = 0; i < RSND_DVC_CHANNELS; i++)
87 val[i] = dvc->volume.cfg.max;
88
89 rsnd_mod_write(mod, DVC_VRCTR, 0xff);
90 rsnd_mod_write(mod, DVC_VRPDR, dvc->rup.val << 8 |
91 dvc->rdown.val);
92 /*
93 * FIXME !!
94 * use scale-downed Digital Volume
95 * as Volume Ramp
96 * 7F FFFF -> 3FF
97 */
98 rsnd_mod_write(mod, DVC_VRDBR,
99 0x3ff - (dvc->volume.val[0] >> 13));
100
101 } else {
102 for (i = 0; i < RSND_DVC_CHANNELS; i++)
103 val[i] = dvc->volume.val[i];
104 }
105
1c5d1c98 106 /* Enable Digital Volume */
3539cacf
KM
107 dvucr |= 0x100;
108 rsnd_mod_write(mod, DVC_VOL0R, val[0]);
109 rsnd_mod_write(mod, DVC_VOL1R, val[1]);
cd2b6574 110
1c5d1c98
KM
111 /* Enable Mute */
112 if (mute) {
113 dvucr |= 0x1;
114 rsnd_mod_write(mod, DVC_ZCMCR, mute);
115 }
116
117 rsnd_mod_write(mod, DVC_DVUCR, dvucr);
140bab89
KM
118
119 /* Enable DVC Register access */
120 rsnd_mod_write(mod, DVC_DVUER, 1);
bff58ea4
KM
121}
122
d1f83d6e 123static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod,
2c0fac19 124 struct rsnd_dai_stream *io,
d1f83d6e
KM
125 struct rsnd_priv *priv)
126{
127 struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
128
129 rsnd_kctrl_remove(dvc->volume);
130 rsnd_kctrl_remove(dvc->mute);
131 rsnd_kctrl_remove(dvc->ren);
132 rsnd_kctrl_remove(dvc->rup);
133 rsnd_kctrl_remove(dvc->rdown);
134
135 return 0;
136}
137
bff58ea4 138static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
2c0fac19 139 struct rsnd_dai_stream *io,
690602fc 140 struct rsnd_priv *priv)
bff58ea4 141{
bff58ea4
KM
142 struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
143 struct device *dev = rsnd_priv_to_dev(priv);
144 int dvc_id = rsnd_mod_id(dvc_mod);
145 int src_id = rsnd_mod_id(src_mod);
146 u32 route[] = {
147 [0] = 0x30000,
148 [1] = 0x30001,
149 [2] = 0x40000,
150 [3] = 0x10000,
151 [4] = 0x20000,
152 [5] = 0x40100
153 };
154
155 if (src_id >= ARRAY_SIZE(route)) {
156 dev_err(dev, "DVC%d isn't connected to SRC%d\n", dvc_id, src_id);
157 return -EINVAL;
158 }
159
85642952 160 rsnd_mod_hw_start(dvc_mod);
bff58ea4
KM
161
162 /*
163 * fixme
164 * it doesn't support CTU/MIX
165 */
166 rsnd_mod_write(dvc_mod, CMD_ROUTE_SLCT, route[src_id]);
167
168 rsnd_mod_write(dvc_mod, DVC_SWRSR, 0);
169 rsnd_mod_write(dvc_mod, DVC_SWRSR, 1);
170
171 rsnd_mod_write(dvc_mod, DVC_DVUIR, 1);
172
4e2639ff 173 rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod, io));
bff58ea4 174
bff58ea4 175 /* ch0/ch1 Volume */
b65a7ccc 176 rsnd_dvc_volume_update(io, dvc_mod);
bff58ea4
KM
177
178 rsnd_mod_write(dvc_mod, DVC_DVUIR, 0);
179
f708d944 180 rsnd_adg_set_cmd_timsel_gen2(dvc_mod, io);
bff58ea4
KM
181
182 return 0;
183}
184
185static int rsnd_dvc_quit(struct rsnd_mod *mod,
2c0fac19 186 struct rsnd_dai_stream *io,
690602fc 187 struct rsnd_priv *priv)
bff58ea4 188{
85642952 189 rsnd_mod_hw_stop(mod);
bff58ea4
KM
190
191 return 0;
192}
193
194static int rsnd_dvc_start(struct rsnd_mod *mod,
2c0fac19 195 struct rsnd_dai_stream *io,
690602fc 196 struct rsnd_priv *priv)
bff58ea4
KM
197{
198 rsnd_mod_write(mod, CMD_CTRL, 0x10);
199
200 return 0;
201}
202
203static int rsnd_dvc_stop(struct rsnd_mod *mod,
2c0fac19 204 struct rsnd_dai_stream *io,
690602fc 205 struct rsnd_priv *priv)
bff58ea4
KM
206{
207 rsnd_mod_write(mod, CMD_CTRL, 0);
208
209 return 0;
210}
211
486b09c7 212static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
2c0fac19 213 struct rsnd_dai_stream *io,
486b09c7
KM
214 struct snd_soc_pcm_runtime *rtd)
215{
486b09c7 216 struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
985a4f6e 217 int is_play = rsnd_io_is_play(io);
486b09c7
KM
218 int ret;
219
220 /* Volume */
b65a7ccc 221 ret = rsnd_kctrl_new_m(mod, io, rtd,
985a4f6e 222 is_play ?
486b09c7 223 "DVC Out Playback Volume" : "DVC In Capture Volume",
170a2497 224 rsnd_dvc_volume_update,
ec14af91 225 &dvc->volume, 0x00800000 - 1);
486b09c7
KM
226 if (ret < 0)
227 return ret;
228
cd2b6574 229 /* Mute */
b65a7ccc 230 ret = rsnd_kctrl_new_m(mod, io, rtd,
985a4f6e 231 is_play ?
cd2b6574 232 "DVC Out Mute Switch" : "DVC In Mute Switch",
170a2497 233 rsnd_dvc_volume_update,
ec14af91 234 &dvc->mute, 1);
cd2b6574
KM
235 if (ret < 0)
236 return ret;
237
3539cacf 238 /* Ramp */
b65a7ccc 239 ret = rsnd_kctrl_new_s(mod, io, rtd,
985a4f6e 240 is_play ?
3539cacf 241 "DVC Out Ramp Switch" : "DVC In Ramp Switch",
170a2497 242 rsnd_dvc_volume_update,
3539cacf
KM
243 &dvc->ren, 1);
244 if (ret < 0)
245 return ret;
246
b65a7ccc 247 ret = rsnd_kctrl_new_e(mod, io, rtd,
985a4f6e 248 is_play ?
3539cacf
KM
249 "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate",
250 &dvc->rup,
170a2497 251 rsnd_dvc_volume_update,
3539cacf
KM
252 dvc_ramp_rate, ARRAY_SIZE(dvc_ramp_rate));
253 if (ret < 0)
254 return ret;
255
b65a7ccc 256 ret = rsnd_kctrl_new_e(mod, io, rtd,
985a4f6e 257 is_play ?
3539cacf
KM
258 "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate",
259 &dvc->rdown,
170a2497 260 rsnd_dvc_volume_update,
3539cacf
KM
261 dvc_ramp_rate, ARRAY_SIZE(dvc_ramp_rate));
262
263 if (ret < 0)
264 return ret;
265
486b09c7
KM
266 return 0;
267}
268
9b99e9a7
KM
269static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io,
270 struct rsnd_mod *mod)
72adc61f
KM
271{
272 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
273
274 return rsnd_dma_request_channel(rsnd_dvc_of_node(priv),
275 mod, "tx");
276}
277
bff58ea4 278static struct rsnd_mod_ops rsnd_dvc_ops = {
8aefda50 279 .name = DVC_NAME,
72adc61f 280 .dma_req = rsnd_dvc_dma_req,
d1f83d6e 281 .remove = rsnd_dvc_remove_gen2,
bff58ea4
KM
282 .init = rsnd_dvc_init,
283 .quit = rsnd_dvc_quit,
284 .start = rsnd_dvc_start,
285 .stop = rsnd_dvc_stop,
286 .pcm_new = rsnd_dvc_pcm_new,
287};
288
289struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)
290{
291 if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv)))
292 id = 0;
293
294 return &((struct rsnd_dvc *)(priv->dvc) + id)->mod;
295}
296
34cb6123
KM
297static void rsnd_of_parse_dvc(struct platform_device *pdev,
298 const struct rsnd_of_data *of_data,
299 struct rsnd_priv *priv)
300{
301 struct device_node *node;
302 struct rsnd_dvc_platform_info *dvc_info;
303 struct rcar_snd_info *info = rsnd_priv_to_info(priv);
304 struct device *dev = &pdev->dev;
305 int nr;
306
307 if (!of_data)
308 return;
309
310 node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc");
311 if (!node)
312 return;
313
314 nr = of_get_child_count(node);
315 if (!nr)
316 goto rsnd_of_parse_dvc_end;
317
318 dvc_info = devm_kzalloc(dev,
319 sizeof(struct rsnd_dvc_platform_info) * nr,
320 GFP_KERNEL);
321 if (!dvc_info) {
322 dev_err(dev, "dvc info allocation error\n");
323 goto rsnd_of_parse_dvc_end;
324 }
325
326 info->dvc_info = dvc_info;
327 info->dvc_info_nr = nr;
328
329rsnd_of_parse_dvc_end:
330 of_node_put(node);
331}
332
bff58ea4
KM
333int rsnd_dvc_probe(struct platform_device *pdev,
334 const struct rsnd_of_data *of_data,
335 struct rsnd_priv *priv)
336{
337 struct rcar_snd_info *info = rsnd_priv_to_info(priv);
338 struct device *dev = rsnd_priv_to_dev(priv);
339 struct rsnd_dvc *dvc;
340 struct clk *clk;
341 char name[RSND_DVC_NAME_SIZE];
2f78dd7f 342 int i, nr, ret;
bff58ea4 343
34cb6123
KM
344 rsnd_of_parse_dvc(pdev, of_data, priv);
345
bff58ea4
KM
346 nr = info->dvc_info_nr;
347 if (!nr)
348 return 0;
349
350 /* This driver doesn't support Gen1 at this point */
351 if (rsnd_is_gen1(priv)) {
352 dev_warn(dev, "CMD is not supported on Gen1\n");
353 return -EINVAL;
354 }
355
356 dvc = devm_kzalloc(dev, sizeof(*dvc) * nr, GFP_KERNEL);
357 if (!dvc) {
358 dev_err(dev, "CMD allocate failed\n");
359 return -ENOMEM;
360 }
361
362 priv->dvc_nr = nr;
363 priv->dvc = dvc;
364
365 for_each_rsnd_dvc(dvc, priv, i) {
8aefda50
KM
366 snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d",
367 DVC_NAME, i);
bff58ea4
KM
368
369 clk = devm_clk_get(dev, name);
370 if (IS_ERR(clk))
371 return PTR_ERR(clk);
372
373 dvc->info = &info->dvc_info[i];
bff58ea4 374
2099bc8e 375 ret = rsnd_mod_init(priv, &dvc->mod, &rsnd_dvc_ops,
85642952 376 clk, RSND_MOD_DVC, i);
2f78dd7f
KM
377 if (ret)
378 return ret;
bff58ea4
KM
379 }
380
381 return 0;
382}
2f78dd7f
KM
383
384void rsnd_dvc_remove(struct platform_device *pdev,
385 struct rsnd_priv *priv)
386{
387 struct rsnd_dvc *dvc;
388 int i;
389
390 for_each_rsnd_dvc(dvc, priv, i) {
391 rsnd_mod_quit(&dvc->mod);
392 }
393}