1*c087a94bSLad Prabhakar // SPDX-License-Identifier: GPL-2.0 2*c087a94bSLad Prabhakar // 3*c087a94bSLad Prabhakar // Renesas R-Car DVC support 4*c087a94bSLad Prabhakar // 5*c087a94bSLad Prabhakar // Copyright (C) 2014 Renesas Solutions Corp. 6*c087a94bSLad Prabhakar // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 7*c087a94bSLad Prabhakar 8*c087a94bSLad Prabhakar /* 9*c087a94bSLad Prabhakar * Playback Volume 10*c087a94bSLad Prabhakar * amixer set "DVC Out" 100% 11*c087a94bSLad Prabhakar * 12*c087a94bSLad Prabhakar * Capture Volume 13*c087a94bSLad Prabhakar * amixer set "DVC In" 100% 14*c087a94bSLad Prabhakar * 15*c087a94bSLad Prabhakar * Playback Mute 16*c087a94bSLad Prabhakar * amixer set "DVC Out Mute" on 17*c087a94bSLad Prabhakar * 18*c087a94bSLad Prabhakar * Capture Mute 19*c087a94bSLad Prabhakar * amixer set "DVC In Mute" on 20*c087a94bSLad Prabhakar * 21*c087a94bSLad Prabhakar * Volume Ramp 22*c087a94bSLad Prabhakar * amixer set "DVC Out Ramp Up Rate" "0.125 dB/64 steps" 23*c087a94bSLad Prabhakar * amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps" 24*c087a94bSLad Prabhakar * amixer set "DVC Out Ramp" on 25*c087a94bSLad Prabhakar * aplay xxx.wav & 26*c087a94bSLad Prabhakar * amixer set "DVC Out" 80% // Volume Down 27*c087a94bSLad Prabhakar * amixer set "DVC Out" 100% // Volume Up 28*c087a94bSLad Prabhakar */ 29*c087a94bSLad Prabhakar 30*c087a94bSLad Prabhakar #include "rsnd.h" 31*c087a94bSLad Prabhakar 32*c087a94bSLad Prabhakar #define RSND_DVC_NAME_SIZE 16 33*c087a94bSLad Prabhakar 34*c087a94bSLad Prabhakar #define DVC_NAME "dvc" 35*c087a94bSLad Prabhakar 36*c087a94bSLad Prabhakar struct rsnd_dvc { 37*c087a94bSLad Prabhakar struct rsnd_mod mod; 38*c087a94bSLad Prabhakar struct rsnd_kctrl_cfg_m volume; 39*c087a94bSLad Prabhakar struct rsnd_kctrl_cfg_m mute; 40*c087a94bSLad Prabhakar struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */ 41*c087a94bSLad Prabhakar struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */ 42*c087a94bSLad Prabhakar struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */ 43*c087a94bSLad Prabhakar }; 44*c087a94bSLad Prabhakar 45*c087a94bSLad Prabhakar #define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id) 46*c087a94bSLad Prabhakar #define rsnd_dvc_nr(priv) ((priv)->dvc_nr) 47*c087a94bSLad Prabhakar 48*c087a94bSLad Prabhakar #define rsnd_mod_to_dvc(_mod) \ 49*c087a94bSLad Prabhakar container_of((_mod), struct rsnd_dvc, mod) 50*c087a94bSLad Prabhakar 51*c087a94bSLad Prabhakar #define for_each_rsnd_dvc(pos, priv, i) \ 52*c087a94bSLad Prabhakar for ((i) = 0; \ 53*c087a94bSLad Prabhakar ((i) < rsnd_dvc_nr(priv)) && \ 54*c087a94bSLad Prabhakar ((pos) = (struct rsnd_dvc *)(priv)->dvc + i); \ 55*c087a94bSLad Prabhakar i++) 56*c087a94bSLad Prabhakar 57*c087a94bSLad Prabhakar static void rsnd_dvc_activation(struct rsnd_mod *mod) 58*c087a94bSLad Prabhakar { 59*c087a94bSLad Prabhakar rsnd_mod_write(mod, DVC_SWRSR, 0); 60*c087a94bSLad Prabhakar rsnd_mod_write(mod, DVC_SWRSR, 1); 61*c087a94bSLad Prabhakar } 62*c087a94bSLad Prabhakar 63*c087a94bSLad Prabhakar static void rsnd_dvc_halt(struct rsnd_mod *mod) 64*c087a94bSLad Prabhakar { 65*c087a94bSLad Prabhakar rsnd_mod_write(mod, DVC_DVUIR, 1); 66*c087a94bSLad Prabhakar rsnd_mod_write(mod, DVC_SWRSR, 0); 67*c087a94bSLad Prabhakar } 68*c087a94bSLad Prabhakar 69*c087a94bSLad Prabhakar #define rsnd_dvc_get_vrpdr(dvc) (rsnd_kctrl_vals(dvc->rup) << 8 | \ 70*c087a94bSLad Prabhakar rsnd_kctrl_vals(dvc->rdown)) 71*c087a94bSLad Prabhakar #define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (rsnd_kctrl_valm(dvc->volume, 0) >> 13)) 72*c087a94bSLad Prabhakar 73*c087a94bSLad Prabhakar static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io, 74*c087a94bSLad Prabhakar struct rsnd_mod *mod) 75*c087a94bSLad Prabhakar { 76*c087a94bSLad Prabhakar struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); 77*c087a94bSLad Prabhakar u32 val[RSND_MAX_CHANNELS]; 78*c087a94bSLad Prabhakar int i; 79*c087a94bSLad Prabhakar 80*c087a94bSLad Prabhakar /* Enable Ramp */ 81*c087a94bSLad Prabhakar if (rsnd_kctrl_vals(dvc->ren)) 82*c087a94bSLad Prabhakar for (i = 0; i < RSND_MAX_CHANNELS; i++) 83*c087a94bSLad Prabhakar val[i] = rsnd_kctrl_max(dvc->volume); 84*c087a94bSLad Prabhakar else 85*c087a94bSLad Prabhakar for (i = 0; i < RSND_MAX_CHANNELS; i++) 86*c087a94bSLad Prabhakar val[i] = rsnd_kctrl_valm(dvc->volume, i); 87*c087a94bSLad Prabhakar 88*c087a94bSLad Prabhakar /* Enable Digital Volume */ 89*c087a94bSLad Prabhakar for (i = 0; i < RSND_MAX_CHANNELS; i++) 90*c087a94bSLad Prabhakar rsnd_mod_write(mod, DVC_VOLxR(i), val[i]); 91*c087a94bSLad Prabhakar } 92*c087a94bSLad Prabhakar 93*c087a94bSLad Prabhakar static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io, 94*c087a94bSLad Prabhakar struct rsnd_mod *mod) 95*c087a94bSLad Prabhakar { 96*c087a94bSLad Prabhakar struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); 97*c087a94bSLad Prabhakar u32 adinr = 0; 98*c087a94bSLad Prabhakar u32 dvucr = 0; 99*c087a94bSLad Prabhakar u32 vrctr = 0; 100*c087a94bSLad Prabhakar u32 vrpdr = 0; 101*c087a94bSLad Prabhakar u32 vrdbr = 0; 102*c087a94bSLad Prabhakar 103*c087a94bSLad Prabhakar adinr = rsnd_get_adinr_bit(mod, io) | 104*c087a94bSLad Prabhakar rsnd_runtime_channel_after_ctu(io); 105*c087a94bSLad Prabhakar 106*c087a94bSLad Prabhakar /* Enable Digital Volume, Zero Cross Mute Mode */ 107*c087a94bSLad Prabhakar dvucr |= 0x101; 108*c087a94bSLad Prabhakar 109*c087a94bSLad Prabhakar /* Enable Ramp */ 110*c087a94bSLad Prabhakar if (rsnd_kctrl_vals(dvc->ren)) { 111*c087a94bSLad Prabhakar dvucr |= 0x10; 112*c087a94bSLad Prabhakar 113*c087a94bSLad Prabhakar /* 114*c087a94bSLad Prabhakar * FIXME !! 115*c087a94bSLad Prabhakar * use scale-downed Digital Volume 116*c087a94bSLad Prabhakar * as Volume Ramp 117*c087a94bSLad Prabhakar * 7F FFFF -> 3FF 118*c087a94bSLad Prabhakar */ 119*c087a94bSLad Prabhakar vrctr = 0xff; 120*c087a94bSLad Prabhakar vrpdr = rsnd_dvc_get_vrpdr(dvc); 121*c087a94bSLad Prabhakar vrdbr = rsnd_dvc_get_vrdbr(dvc); 122*c087a94bSLad Prabhakar } 123*c087a94bSLad Prabhakar 124*c087a94bSLad Prabhakar /* Initialize operation */ 125*c087a94bSLad Prabhakar rsnd_mod_write(mod, DVC_DVUIR, 1); 126*c087a94bSLad Prabhakar 127*c087a94bSLad Prabhakar /* General Information */ 128*c087a94bSLad Prabhakar rsnd_mod_write(mod, DVC_ADINR, adinr); 129*c087a94bSLad Prabhakar rsnd_mod_write(mod, DVC_DVUCR, dvucr); 130*c087a94bSLad Prabhakar 131*c087a94bSLad Prabhakar /* Volume Ramp Parameter */ 132*c087a94bSLad Prabhakar rsnd_mod_write(mod, DVC_VRCTR, vrctr); 133*c087a94bSLad Prabhakar rsnd_mod_write(mod, DVC_VRPDR, vrpdr); 134*c087a94bSLad Prabhakar rsnd_mod_write(mod, DVC_VRDBR, vrdbr); 135*c087a94bSLad Prabhakar 136*c087a94bSLad Prabhakar /* Digital Volume Function Parameter */ 137*c087a94bSLad Prabhakar rsnd_dvc_volume_parameter(io, mod); 138*c087a94bSLad Prabhakar 139*c087a94bSLad Prabhakar /* cancel operation */ 140*c087a94bSLad Prabhakar rsnd_mod_write(mod, DVC_DVUIR, 0); 141*c087a94bSLad Prabhakar } 142*c087a94bSLad Prabhakar 143*c087a94bSLad Prabhakar static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io, 144*c087a94bSLad Prabhakar struct rsnd_mod *mod) 145*c087a94bSLad Prabhakar { 146*c087a94bSLad Prabhakar struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); 147*c087a94bSLad Prabhakar u32 zcmcr = 0; 148*c087a94bSLad Prabhakar u32 vrpdr = 0; 149*c087a94bSLad Prabhakar u32 vrdbr = 0; 150*c087a94bSLad Prabhakar int i; 151*c087a94bSLad Prabhakar 152*c087a94bSLad Prabhakar for (i = 0; i < rsnd_kctrl_size(dvc->mute); i++) 153*c087a94bSLad Prabhakar zcmcr |= (!!rsnd_kctrl_valm(dvc->mute, i)) << i; 154*c087a94bSLad Prabhakar 155*c087a94bSLad Prabhakar if (rsnd_kctrl_vals(dvc->ren)) { 156*c087a94bSLad Prabhakar vrpdr = rsnd_dvc_get_vrpdr(dvc); 157*c087a94bSLad Prabhakar vrdbr = rsnd_dvc_get_vrdbr(dvc); 158*c087a94bSLad Prabhakar } 159*c087a94bSLad Prabhakar 160*c087a94bSLad Prabhakar /* Disable DVC Register access */ 161*c087a94bSLad Prabhakar rsnd_mod_write(mod, DVC_DVUER, 0); 162*c087a94bSLad Prabhakar 163*c087a94bSLad Prabhakar /* Zero Cross Mute Function */ 164*c087a94bSLad Prabhakar rsnd_mod_write(mod, DVC_ZCMCR, zcmcr); 165*c087a94bSLad Prabhakar 166*c087a94bSLad Prabhakar /* Volume Ramp Function */ 167*c087a94bSLad Prabhakar rsnd_mod_write(mod, DVC_VRPDR, vrpdr); 168*c087a94bSLad Prabhakar rsnd_mod_write(mod, DVC_VRDBR, vrdbr); 169*c087a94bSLad Prabhakar /* add DVC_VRWTR here */ 170*c087a94bSLad Prabhakar 171*c087a94bSLad Prabhakar /* Digital Volume Function Parameter */ 172*c087a94bSLad Prabhakar rsnd_dvc_volume_parameter(io, mod); 173*c087a94bSLad Prabhakar 174*c087a94bSLad Prabhakar /* Enable DVC Register access */ 175*c087a94bSLad Prabhakar rsnd_mod_write(mod, DVC_DVUER, 1); 176*c087a94bSLad Prabhakar } 177*c087a94bSLad Prabhakar 178*c087a94bSLad Prabhakar static int rsnd_dvc_probe_(struct rsnd_mod *mod, 179*c087a94bSLad Prabhakar struct rsnd_dai_stream *io, 180*c087a94bSLad Prabhakar struct rsnd_priv *priv) 181*c087a94bSLad Prabhakar { 182*c087a94bSLad Prabhakar return rsnd_cmd_attach(io, rsnd_mod_id(mod)); 183*c087a94bSLad Prabhakar } 184*c087a94bSLad Prabhakar 185*c087a94bSLad Prabhakar static int rsnd_dvc_init(struct rsnd_mod *mod, 186*c087a94bSLad Prabhakar struct rsnd_dai_stream *io, 187*c087a94bSLad Prabhakar struct rsnd_priv *priv) 188*c087a94bSLad Prabhakar { 189*c087a94bSLad Prabhakar int ret; 190*c087a94bSLad Prabhakar 191*c087a94bSLad Prabhakar ret = rsnd_mod_power_on(mod); 192*c087a94bSLad Prabhakar if (ret < 0) 193*c087a94bSLad Prabhakar return ret; 194*c087a94bSLad Prabhakar 195*c087a94bSLad Prabhakar rsnd_dvc_activation(mod); 196*c087a94bSLad Prabhakar 197*c087a94bSLad Prabhakar rsnd_dvc_volume_init(io, mod); 198*c087a94bSLad Prabhakar 199*c087a94bSLad Prabhakar rsnd_dvc_volume_update(io, mod); 200*c087a94bSLad Prabhakar 201*c087a94bSLad Prabhakar return 0; 202*c087a94bSLad Prabhakar } 203*c087a94bSLad Prabhakar 204*c087a94bSLad Prabhakar static int rsnd_dvc_quit(struct rsnd_mod *mod, 205*c087a94bSLad Prabhakar struct rsnd_dai_stream *io, 206*c087a94bSLad Prabhakar struct rsnd_priv *priv) 207*c087a94bSLad Prabhakar { 208*c087a94bSLad Prabhakar rsnd_dvc_halt(mod); 209*c087a94bSLad Prabhakar 210*c087a94bSLad Prabhakar rsnd_mod_power_off(mod); 211*c087a94bSLad Prabhakar 212*c087a94bSLad Prabhakar return 0; 213*c087a94bSLad Prabhakar } 214*c087a94bSLad Prabhakar 215*c087a94bSLad Prabhakar static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, 216*c087a94bSLad Prabhakar struct rsnd_dai_stream *io, 217*c087a94bSLad Prabhakar struct snd_soc_pcm_runtime *rtd) 218*c087a94bSLad Prabhakar { 219*c087a94bSLad Prabhakar struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); 220*c087a94bSLad Prabhakar struct rsnd_dai *rdai = rsnd_io_to_rdai(io); 221*c087a94bSLad Prabhakar int is_play = rsnd_io_is_play(io); 222*c087a94bSLad Prabhakar int channels = rsnd_rdai_channels_get(rdai); 223*c087a94bSLad Prabhakar int ret; 224*c087a94bSLad Prabhakar 225*c087a94bSLad Prabhakar /* Volume */ 226*c087a94bSLad Prabhakar ret = rsnd_kctrl_new_m(mod, io, rtd, 227*c087a94bSLad Prabhakar is_play ? 228*c087a94bSLad Prabhakar "DVC Out Playback Volume" : "DVC In Capture Volume", 229*c087a94bSLad Prabhakar rsnd_kctrl_accept_anytime, 230*c087a94bSLad Prabhakar rsnd_dvc_volume_update, 231*c087a94bSLad Prabhakar &dvc->volume, channels, 232*c087a94bSLad Prabhakar 0x00800000 - 1); 233*c087a94bSLad Prabhakar if (ret < 0) 234*c087a94bSLad Prabhakar return ret; 235*c087a94bSLad Prabhakar 236*c087a94bSLad Prabhakar /* Mute */ 237*c087a94bSLad Prabhakar ret = rsnd_kctrl_new_m(mod, io, rtd, 238*c087a94bSLad Prabhakar is_play ? 239*c087a94bSLad Prabhakar "DVC Out Mute Switch" : "DVC In Mute Switch", 240*c087a94bSLad Prabhakar rsnd_kctrl_accept_anytime, 241*c087a94bSLad Prabhakar rsnd_dvc_volume_update, 242*c087a94bSLad Prabhakar &dvc->mute, channels, 243*c087a94bSLad Prabhakar 1); 244*c087a94bSLad Prabhakar if (ret < 0) 245*c087a94bSLad Prabhakar return ret; 246*c087a94bSLad Prabhakar 247*c087a94bSLad Prabhakar /* Ramp */ 248*c087a94bSLad Prabhakar ret = rsnd_kctrl_new_s(mod, io, rtd, 249*c087a94bSLad Prabhakar is_play ? 250*c087a94bSLad Prabhakar "DVC Out Ramp Switch" : "DVC In Ramp Switch", 251*c087a94bSLad Prabhakar rsnd_kctrl_accept_anytime, 252*c087a94bSLad Prabhakar rsnd_dvc_volume_update, 253*c087a94bSLad Prabhakar &dvc->ren, 1); 254*c087a94bSLad Prabhakar if (ret < 0) 255*c087a94bSLad Prabhakar return ret; 256*c087a94bSLad Prabhakar 257*c087a94bSLad Prabhakar ret = rsnd_kctrl_new_e(mod, io, rtd, 258*c087a94bSLad Prabhakar is_play ? 259*c087a94bSLad Prabhakar "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate", 260*c087a94bSLad Prabhakar rsnd_kctrl_accept_anytime, 261*c087a94bSLad Prabhakar rsnd_dvc_volume_update, 262*c087a94bSLad Prabhakar &dvc->rup, 263*c087a94bSLad Prabhakar volume_ramp_rate, 264*c087a94bSLad Prabhakar VOLUME_RAMP_MAX_DVC); 265*c087a94bSLad Prabhakar if (ret < 0) 266*c087a94bSLad Prabhakar return ret; 267*c087a94bSLad Prabhakar 268*c087a94bSLad Prabhakar ret = rsnd_kctrl_new_e(mod, io, rtd, 269*c087a94bSLad Prabhakar is_play ? 270*c087a94bSLad Prabhakar "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate", 271*c087a94bSLad Prabhakar rsnd_kctrl_accept_anytime, 272*c087a94bSLad Prabhakar rsnd_dvc_volume_update, 273*c087a94bSLad Prabhakar &dvc->rdown, 274*c087a94bSLad Prabhakar volume_ramp_rate, 275*c087a94bSLad Prabhakar VOLUME_RAMP_MAX_DVC); 276*c087a94bSLad Prabhakar 277*c087a94bSLad Prabhakar if (ret < 0) 278*c087a94bSLad Prabhakar return ret; 279*c087a94bSLad Prabhakar 280*c087a94bSLad Prabhakar return 0; 281*c087a94bSLad Prabhakar } 282*c087a94bSLad Prabhakar 283*c087a94bSLad Prabhakar static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io, 284*c087a94bSLad Prabhakar struct rsnd_mod *mod) 285*c087a94bSLad Prabhakar { 286*c087a94bSLad Prabhakar struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 287*c087a94bSLad Prabhakar 288*c087a94bSLad Prabhakar return rsnd_dma_request_channel(rsnd_dvc_of_node(priv), 289*c087a94bSLad Prabhakar DVC_NAME, mod, "tx"); 290*c087a94bSLad Prabhakar } 291*c087a94bSLad Prabhakar 292*c087a94bSLad Prabhakar #ifdef CONFIG_DEBUG_FS 293*c087a94bSLad Prabhakar static void rsnd_dvc_debug_info(struct seq_file *m, 294*c087a94bSLad Prabhakar struct rsnd_dai_stream *io, 295*c087a94bSLad Prabhakar struct rsnd_mod *mod) 296*c087a94bSLad Prabhakar { 297*c087a94bSLad Prabhakar rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU, 298*c087a94bSLad Prabhakar 0xe00 + rsnd_mod_id(mod) * 0x100, 0x60); 299*c087a94bSLad Prabhakar } 300*c087a94bSLad Prabhakar #define DEBUG_INFO .debug_info = rsnd_dvc_debug_info 301*c087a94bSLad Prabhakar #else 302*c087a94bSLad Prabhakar #define DEBUG_INFO 303*c087a94bSLad Prabhakar #endif 304*c087a94bSLad Prabhakar 305*c087a94bSLad Prabhakar static struct rsnd_mod_ops rsnd_dvc_ops = { 306*c087a94bSLad Prabhakar .name = DVC_NAME, 307*c087a94bSLad Prabhakar .dma_req = rsnd_dvc_dma_req, 308*c087a94bSLad Prabhakar .probe = rsnd_dvc_probe_, 309*c087a94bSLad Prabhakar .init = rsnd_dvc_init, 310*c087a94bSLad Prabhakar .quit = rsnd_dvc_quit, 311*c087a94bSLad Prabhakar .pcm_new = rsnd_dvc_pcm_new, 312*c087a94bSLad Prabhakar .get_status = rsnd_mod_get_status, 313*c087a94bSLad Prabhakar DEBUG_INFO 314*c087a94bSLad Prabhakar }; 315*c087a94bSLad Prabhakar 316*c087a94bSLad Prabhakar struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) 317*c087a94bSLad Prabhakar { 318*c087a94bSLad Prabhakar if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv))) 319*c087a94bSLad Prabhakar id = 0; 320*c087a94bSLad Prabhakar 321*c087a94bSLad Prabhakar return rsnd_mod_get(rsnd_dvc_get(priv, id)); 322*c087a94bSLad Prabhakar } 323*c087a94bSLad Prabhakar 324*c087a94bSLad Prabhakar int rsnd_dvc_probe(struct rsnd_priv *priv) 325*c087a94bSLad Prabhakar { 326*c087a94bSLad Prabhakar struct device_node *node; 327*c087a94bSLad Prabhakar struct device_node *np; 328*c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv); 329*c087a94bSLad Prabhakar struct rsnd_dvc *dvc; 330*c087a94bSLad Prabhakar struct clk *clk; 331*c087a94bSLad Prabhakar char name[RSND_DVC_NAME_SIZE]; 332*c087a94bSLad Prabhakar int i, nr, ret; 333*c087a94bSLad Prabhakar 334*c087a94bSLad Prabhakar node = rsnd_dvc_of_node(priv); 335*c087a94bSLad Prabhakar if (!node) 336*c087a94bSLad Prabhakar return 0; /* not used is not error */ 337*c087a94bSLad Prabhakar 338*c087a94bSLad Prabhakar nr = of_get_child_count(node); 339*c087a94bSLad Prabhakar if (!nr) { 340*c087a94bSLad Prabhakar ret = -EINVAL; 341*c087a94bSLad Prabhakar goto rsnd_dvc_probe_done; 342*c087a94bSLad Prabhakar } 343*c087a94bSLad Prabhakar 344*c087a94bSLad Prabhakar dvc = devm_kcalloc(dev, nr, sizeof(*dvc), GFP_KERNEL); 345*c087a94bSLad Prabhakar if (!dvc) { 346*c087a94bSLad Prabhakar ret = -ENOMEM; 347*c087a94bSLad Prabhakar goto rsnd_dvc_probe_done; 348*c087a94bSLad Prabhakar } 349*c087a94bSLad Prabhakar 350*c087a94bSLad Prabhakar priv->dvc_nr = nr; 351*c087a94bSLad Prabhakar priv->dvc = dvc; 352*c087a94bSLad Prabhakar 353*c087a94bSLad Prabhakar i = 0; 354*c087a94bSLad Prabhakar ret = 0; 355*c087a94bSLad Prabhakar for_each_child_of_node(node, np) { 356*c087a94bSLad Prabhakar dvc = rsnd_dvc_get(priv, i); 357*c087a94bSLad Prabhakar 358*c087a94bSLad Prabhakar snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d", 359*c087a94bSLad Prabhakar DVC_NAME, i); 360*c087a94bSLad Prabhakar 361*c087a94bSLad Prabhakar clk = devm_clk_get(dev, name); 362*c087a94bSLad Prabhakar if (IS_ERR(clk)) { 363*c087a94bSLad Prabhakar ret = PTR_ERR(clk); 364*c087a94bSLad Prabhakar of_node_put(np); 365*c087a94bSLad Prabhakar goto rsnd_dvc_probe_done; 366*c087a94bSLad Prabhakar } 367*c087a94bSLad Prabhakar 368*c087a94bSLad Prabhakar ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops, 369*c087a94bSLad Prabhakar clk, RSND_MOD_DVC, i); 370*c087a94bSLad Prabhakar if (ret) { 371*c087a94bSLad Prabhakar of_node_put(np); 372*c087a94bSLad Prabhakar goto rsnd_dvc_probe_done; 373*c087a94bSLad Prabhakar } 374*c087a94bSLad Prabhakar 375*c087a94bSLad Prabhakar i++; 376*c087a94bSLad Prabhakar } 377*c087a94bSLad Prabhakar 378*c087a94bSLad Prabhakar rsnd_dvc_probe_done: 379*c087a94bSLad Prabhakar of_node_put(node); 380*c087a94bSLad Prabhakar 381*c087a94bSLad Prabhakar return ret; 382*c087a94bSLad Prabhakar } 383*c087a94bSLad Prabhakar 384*c087a94bSLad Prabhakar void rsnd_dvc_remove(struct rsnd_priv *priv) 385*c087a94bSLad Prabhakar { 386*c087a94bSLad Prabhakar struct rsnd_dvc *dvc; 387*c087a94bSLad Prabhakar int i; 388*c087a94bSLad Prabhakar 389*c087a94bSLad Prabhakar for_each_rsnd_dvc(dvc, priv, i) { 390*c087a94bSLad Prabhakar rsnd_mod_quit(rsnd_mod_get(dvc)); 391*c087a94bSLad Prabhakar } 392*c087a94bSLad Prabhakar } 393