mix.c (8281B)
1// SPDX-License-Identifier: GPL-2.0 2// 3// mix.c 4// 5// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 6 7/* 8 * CTUn MIXn 9 * +------+ +------+ 10 * [SRC3 / SRC6] -> |CTU n0| -> [MIX n0| -> 11 * [SRC4 / SRC9] -> |CTU n1| -> [MIX n1| -> 12 * [SRC0 / SRC1] -> |CTU n2| -> [MIX n2| -> 13 * [SRC2 / SRC5] -> |CTU n3| -> [MIX n3| -> 14 * +------+ +------+ 15 * 16 * ex) 17 * DAI0 : playback = <&src0 &ctu02 &mix0 &dvc0 &ssi0>; 18 * DAI1 : playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>; 19 * 20 * MIX Volume 21 * amixer set "MIX",0 100% // DAI0 Volume 22 * amixer set "MIX",1 100% // DAI1 Volume 23 * 24 * Volume Ramp 25 * amixer set "MIX Ramp Up Rate" "0.125 dB/1 step" 26 * amixer set "MIX Ramp Down Rate" "4 dB/1 step" 27 * amixer set "MIX Ramp" on 28 * aplay xxx.wav & 29 * amixer set "MIX",0 80% // DAI0 Volume Down 30 * amixer set "MIX",1 100% // DAI1 Volume Up 31 */ 32 33#include "rsnd.h" 34 35#define MIX_NAME_SIZE 16 36#define MIX_NAME "mix" 37 38struct rsnd_mix { 39 struct rsnd_mod mod; 40 struct rsnd_kctrl_cfg_s volumeA; /* MDBAR */ 41 struct rsnd_kctrl_cfg_s volumeB; /* MDBBR */ 42 struct rsnd_kctrl_cfg_s volumeC; /* MDBCR */ 43 struct rsnd_kctrl_cfg_s volumeD; /* MDBDR */ 44 struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */ 45 struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */ 46 struct rsnd_kctrl_cfg_s rdw; /* Ramp Rate Down */ 47 u32 flags; 48}; 49 50#define ONCE_KCTRL_INITIALIZED (1 << 0) 51#define HAS_VOLA (1 << 1) 52#define HAS_VOLB (1 << 2) 53#define HAS_VOLC (1 << 3) 54#define HAS_VOLD (1 << 4) 55 56#define VOL_MAX 0x3ff 57 58#define rsnd_mod_to_mix(_mod) \ 59 container_of((_mod), struct rsnd_mix, mod) 60 61#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id) 62#define rsnd_mix_nr(priv) ((priv)->mix_nr) 63#define for_each_rsnd_mix(pos, priv, i) \ 64 for ((i) = 0; \ 65 ((i) < rsnd_mix_nr(priv)) && \ 66 ((pos) = (struct rsnd_mix *)(priv)->mix + i); \ 67 i++) 68 69static void rsnd_mix_activation(struct rsnd_mod *mod) 70{ 71 rsnd_mod_write(mod, MIX_SWRSR, 0); 72 rsnd_mod_write(mod, MIX_SWRSR, 1); 73} 74 75static void rsnd_mix_halt(struct rsnd_mod *mod) 76{ 77 rsnd_mod_write(mod, MIX_MIXIR, 1); 78 rsnd_mod_write(mod, MIX_SWRSR, 0); 79} 80 81#define rsnd_mix_get_vol(mix, X) \ 82 rsnd_flags_has(mix, HAS_VOL##X) ? \ 83 (VOL_MAX - rsnd_kctrl_vals(mix->volume##X)) : 0 84static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io, 85 struct rsnd_mod *mod) 86{ 87 struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 88 struct device *dev = rsnd_priv_to_dev(priv); 89 struct rsnd_mix *mix = rsnd_mod_to_mix(mod); 90 u32 volA = rsnd_mix_get_vol(mix, A); 91 u32 volB = rsnd_mix_get_vol(mix, B); 92 u32 volC = rsnd_mix_get_vol(mix, C); 93 u32 volD = rsnd_mix_get_vol(mix, D); 94 95 dev_dbg(dev, "MIX A/B/C/D = %02x/%02x/%02x/%02x\n", 96 volA, volB, volC, volD); 97 98 rsnd_mod_write(mod, MIX_MDBAR, volA); 99 rsnd_mod_write(mod, MIX_MDBBR, volB); 100 rsnd_mod_write(mod, MIX_MDBCR, volC); 101 rsnd_mod_write(mod, MIX_MDBDR, volD); 102} 103 104static void rsnd_mix_volume_init(struct rsnd_dai_stream *io, 105 struct rsnd_mod *mod) 106{ 107 struct rsnd_mix *mix = rsnd_mod_to_mix(mod); 108 109 rsnd_mod_write(mod, MIX_MIXIR, 1); 110 111 /* General Information */ 112 rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io)); 113 114 /* volume step */ 115 rsnd_mod_write(mod, MIX_MIXMR, rsnd_kctrl_vals(mix->ren)); 116 rsnd_mod_write(mod, MIX_MVPDR, rsnd_kctrl_vals(mix->rup) << 8 | 117 rsnd_kctrl_vals(mix->rdw)); 118 119 /* common volume parameter */ 120 rsnd_mix_volume_parameter(io, mod); 121 122 rsnd_mod_write(mod, MIX_MIXIR, 0); 123} 124 125static void rsnd_mix_volume_update(struct rsnd_dai_stream *io, 126 struct rsnd_mod *mod) 127{ 128 /* Disable MIX dB setting */ 129 rsnd_mod_write(mod, MIX_MDBER, 0); 130 131 /* common volume parameter */ 132 rsnd_mix_volume_parameter(io, mod); 133 134 /* Enable MIX dB setting */ 135 rsnd_mod_write(mod, MIX_MDBER, 1); 136} 137 138static int rsnd_mix_probe_(struct rsnd_mod *mod, 139 struct rsnd_dai_stream *io, 140 struct rsnd_priv *priv) 141{ 142 return rsnd_cmd_attach(io, rsnd_mod_id(mod)); 143} 144 145static int rsnd_mix_init(struct rsnd_mod *mod, 146 struct rsnd_dai_stream *io, 147 struct rsnd_priv *priv) 148{ 149 rsnd_mod_power_on(mod); 150 151 rsnd_mix_activation(mod); 152 153 rsnd_mix_volume_init(io, mod); 154 155 rsnd_mix_volume_update(io, mod); 156 157 return 0; 158} 159 160static int rsnd_mix_quit(struct rsnd_mod *mod, 161 struct rsnd_dai_stream *io, 162 struct rsnd_priv *priv) 163{ 164 rsnd_mix_halt(mod); 165 166 rsnd_mod_power_off(mod); 167 168 return 0; 169} 170 171static int rsnd_mix_pcm_new(struct rsnd_mod *mod, 172 struct rsnd_dai_stream *io, 173 struct snd_soc_pcm_runtime *rtd) 174{ 175 struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 176 struct device *dev = rsnd_priv_to_dev(priv); 177 struct rsnd_mix *mix = rsnd_mod_to_mix(mod); 178 struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); 179 struct rsnd_kctrl_cfg_s *volume; 180 int ret; 181 182 switch (rsnd_mod_id(src_mod)) { 183 case 3: 184 case 6: /* MDBAR */ 185 volume = &mix->volumeA; 186 rsnd_flags_set(mix, HAS_VOLA); 187 break; 188 case 4: 189 case 9: /* MDBBR */ 190 volume = &mix->volumeB; 191 rsnd_flags_set(mix, HAS_VOLB); 192 break; 193 case 0: 194 case 1: /* MDBCR */ 195 volume = &mix->volumeC; 196 rsnd_flags_set(mix, HAS_VOLC); 197 break; 198 case 2: 199 case 5: /* MDBDR */ 200 volume = &mix->volumeD; 201 rsnd_flags_set(mix, HAS_VOLD); 202 break; 203 default: 204 dev_err(dev, "unknown SRC is connected\n"); 205 return -EINVAL; 206 } 207 208 /* Volume */ 209 ret = rsnd_kctrl_new_s(mod, io, rtd, 210 "MIX Playback Volume", 211 rsnd_kctrl_accept_anytime, 212 rsnd_mix_volume_update, 213 volume, VOL_MAX); 214 if (ret < 0) 215 return ret; 216 rsnd_kctrl_vals(*volume) = VOL_MAX; 217 218 if (rsnd_flags_has(mix, ONCE_KCTRL_INITIALIZED)) 219 return ret; 220 221 /* Ramp */ 222 ret = rsnd_kctrl_new_s(mod, io, rtd, 223 "MIX Ramp Switch", 224 rsnd_kctrl_accept_anytime, 225 rsnd_mix_volume_update, 226 &mix->ren, 1); 227 if (ret < 0) 228 return ret; 229 230 ret = rsnd_kctrl_new_e(mod, io, rtd, 231 "MIX Ramp Up Rate", 232 rsnd_kctrl_accept_anytime, 233 rsnd_mix_volume_update, 234 &mix->rup, 235 volume_ramp_rate, 236 VOLUME_RAMP_MAX_MIX); 237 if (ret < 0) 238 return ret; 239 240 ret = rsnd_kctrl_new_e(mod, io, rtd, 241 "MIX Ramp Down Rate", 242 rsnd_kctrl_accept_anytime, 243 rsnd_mix_volume_update, 244 &mix->rdw, 245 volume_ramp_rate, 246 VOLUME_RAMP_MAX_MIX); 247 248 rsnd_flags_set(mix, ONCE_KCTRL_INITIALIZED); 249 250 return ret; 251} 252 253#ifdef CONFIG_DEBUG_FS 254static void rsnd_mix_debug_info(struct seq_file *m, 255 struct rsnd_dai_stream *io, 256 struct rsnd_mod *mod) 257{ 258 rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, 259 0xd00 + rsnd_mod_id(mod) * 0x40, 0x30); 260} 261#define DEBUG_INFO .debug_info = rsnd_mix_debug_info 262#else 263#define DEBUG_INFO 264#endif 265 266static struct rsnd_mod_ops rsnd_mix_ops = { 267 .name = MIX_NAME, 268 .probe = rsnd_mix_probe_, 269 .init = rsnd_mix_init, 270 .quit = rsnd_mix_quit, 271 .pcm_new = rsnd_mix_pcm_new, 272 .get_status = rsnd_mod_get_status, 273 DEBUG_INFO 274}; 275 276struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) 277{ 278 if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv))) 279 id = 0; 280 281 return rsnd_mod_get(rsnd_mix_get(priv, id)); 282} 283 284int rsnd_mix_probe(struct rsnd_priv *priv) 285{ 286 struct device_node *node; 287 struct device_node *np; 288 struct device *dev = rsnd_priv_to_dev(priv); 289 struct rsnd_mix *mix; 290 struct clk *clk; 291 char name[MIX_NAME_SIZE]; 292 int i, nr, ret; 293 294 /* This driver doesn't support Gen1 at this point */ 295 if (rsnd_is_gen1(priv)) 296 return 0; 297 298 node = rsnd_mix_of_node(priv); 299 if (!node) 300 return 0; /* not used is not error */ 301 302 nr = of_get_child_count(node); 303 if (!nr) { 304 ret = -EINVAL; 305 goto rsnd_mix_probe_done; 306 } 307 308 mix = devm_kcalloc(dev, nr, sizeof(*mix), GFP_KERNEL); 309 if (!mix) { 310 ret = -ENOMEM; 311 goto rsnd_mix_probe_done; 312 } 313 314 priv->mix_nr = nr; 315 priv->mix = mix; 316 317 i = 0; 318 ret = 0; 319 for_each_child_of_node(node, np) { 320 mix = rsnd_mix_get(priv, i); 321 322 snprintf(name, MIX_NAME_SIZE, "%s.%d", 323 MIX_NAME, i); 324 325 clk = devm_clk_get(dev, name); 326 if (IS_ERR(clk)) { 327 ret = PTR_ERR(clk); 328 of_node_put(np); 329 goto rsnd_mix_probe_done; 330 } 331 332 ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops, 333 clk, RSND_MOD_MIX, i); 334 if (ret) { 335 of_node_put(np); 336 goto rsnd_mix_probe_done; 337 } 338 339 i++; 340 } 341 342rsnd_mix_probe_done: 343 of_node_put(node); 344 345 return ret; 346} 347 348void rsnd_mix_remove(struct rsnd_priv *priv) 349{ 350 struct rsnd_mix *mix; 351 int i; 352 353 for_each_rsnd_mix(mix, priv, i) { 354 rsnd_mod_quit(rsnd_mod_get(mix)); 355 } 356}