cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

adg.c (15345B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Helper routines for R-Car sound ADG.
      4//
      5//  Copyright (C) 2013  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
      6#include <linux/clk-provider.h>
      7#include <linux/clkdev.h>
      8#include "rsnd.h"
      9
     10#define CLKA	0
     11#define CLKB	1
     12#define CLKC	2
     13#define CLKI	3
     14#define CLKMAX	4
     15
     16#define CLKOUT	0
     17#define CLKOUT1	1
     18#define CLKOUT2	2
     19#define CLKOUT3	3
     20#define CLKOUTMAX 4
     21
     22#define BRRx_MASK(x) (0x3FF & x)
     23
     24static struct rsnd_mod_ops adg_ops = {
     25	.name = "adg",
     26};
     27
     28struct rsnd_adg {
     29	struct clk *clk[CLKMAX];
     30	struct clk *clkout[CLKOUTMAX];
     31	struct clk *null_clk;
     32	struct clk_onecell_data onecell;
     33	struct rsnd_mod mod;
     34	int clk_rate[CLKMAX];
     35	u32 flags;
     36	u32 ckr;
     37	u32 rbga;
     38	u32 rbgb;
     39
     40	int rbga_rate_for_441khz; /* RBGA */
     41	int rbgb_rate_for_48khz;  /* RBGB */
     42};
     43
     44#define LRCLK_ASYNC	(1 << 0)
     45#define AUDIO_OUT_48	(1 << 1)
     46
     47#define for_each_rsnd_clk(pos, adg, i)		\
     48	for (i = 0;				\
     49	     (i < CLKMAX) &&			\
     50	     ((pos) = adg->clk[i]);		\
     51	     i++)
     52#define for_each_rsnd_clkout(pos, adg, i)	\
     53	for (i = 0;				\
     54	     (i < CLKOUTMAX) &&			\
     55	     ((pos) = adg->clkout[i]);	\
     56	     i++)
     57#define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
     58
     59static const char * const clk_name[] = {
     60	[CLKA]	= "clk_a",
     61	[CLKB]	= "clk_b",
     62	[CLKC]	= "clk_c",
     63	[CLKI]	= "clk_i",
     64};
     65
     66static u32 rsnd_adg_calculate_rbgx(unsigned long div)
     67{
     68	int i;
     69
     70	if (!div)
     71		return 0;
     72
     73	for (i = 3; i >= 0; i--) {
     74		int ratio = 2 << (i * 2);
     75		if (0 == (div % ratio))
     76			return (u32)((i << 8) | ((div / ratio) - 1));
     77	}
     78
     79	return ~0;
     80}
     81
     82static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
     83{
     84	struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
     85	int id = rsnd_mod_id(ssi_mod);
     86	int ws = id;
     87
     88	if (rsnd_ssi_is_pin_sharing(io)) {
     89		switch (id) {
     90		case 1:
     91		case 2:
     92		case 9:
     93			ws = 0;
     94			break;
     95		case 4:
     96			ws = 3;
     97			break;
     98		case 8:
     99			ws = 7;
    100			break;
    101		}
    102	}
    103
    104	return (0x6 + ws) << 8;
    105}
    106
    107static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
    108				       struct rsnd_dai_stream *io,
    109				       unsigned int target_rate,
    110				       unsigned int *target_val,
    111				       unsigned int *target_en)
    112{
    113	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
    114	struct device *dev = rsnd_priv_to_dev(priv);
    115	int sel;
    116	unsigned int val, en;
    117	unsigned int min, diff;
    118	unsigned int sel_rate[] = {
    119		adg->clk_rate[CLKA],	/* 0000: CLKA */
    120		adg->clk_rate[CLKB],	/* 0001: CLKB */
    121		adg->clk_rate[CLKC],	/* 0010: CLKC */
    122		adg->rbga_rate_for_441khz,	/* 0011: RBGA */
    123		adg->rbgb_rate_for_48khz,	/* 0100: RBGB */
    124	};
    125
    126	min = ~0;
    127	val = 0;
    128	en = 0;
    129	for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
    130		int idx = 0;
    131		int step = 2;
    132		int div;
    133
    134		if (!sel_rate[sel])
    135			continue;
    136
    137		for (div = 2; div <= 98304; div += step) {
    138			diff = abs(target_rate - sel_rate[sel] / div);
    139			if (min > diff) {
    140				val = (sel << 8) | idx;
    141				min = diff;
    142				en = 1 << (sel + 1); /* fixme */
    143			}
    144
    145			/*
    146			 * step of 0_0000 / 0_0001 / 0_1101
    147			 * are out of order
    148			 */
    149			if ((idx > 2) && (idx % 2))
    150				step *= 2;
    151			if (idx == 0x1c) {
    152				div += step;
    153				step *= 2;
    154			}
    155			idx++;
    156		}
    157	}
    158
    159	if (min == ~0) {
    160		dev_err(dev, "no Input clock\n");
    161		return;
    162	}
    163
    164	*target_val = val;
    165	if (target_en)
    166		*target_en = en;
    167}
    168
    169static void rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
    170				       struct rsnd_dai_stream *io,
    171				       unsigned int in_rate,
    172				       unsigned int out_rate,
    173				       u32 *in, u32 *out, u32 *en)
    174{
    175	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
    176	unsigned int target_rate;
    177	u32 *target_val;
    178	u32 _in;
    179	u32 _out;
    180	u32 _en;
    181
    182	/* default = SSI WS */
    183	_in =
    184	_out = rsnd_adg_ssi_ws_timing_gen2(io);
    185
    186	target_rate = 0;
    187	target_val = NULL;
    188	_en = 0;
    189	if (runtime->rate != in_rate) {
    190		target_rate = out_rate;
    191		target_val  = &_out;
    192	} else if (runtime->rate != out_rate) {
    193		target_rate = in_rate;
    194		target_val  = &_in;
    195	}
    196
    197	if (target_rate)
    198		__rsnd_adg_get_timesel_ratio(priv, io,
    199					     target_rate,
    200					     target_val, &_en);
    201
    202	if (in)
    203		*in = _in;
    204	if (out)
    205		*out = _out;
    206	if (en)
    207		*en = _en;
    208}
    209
    210int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
    211				 struct rsnd_dai_stream *io)
    212{
    213	struct rsnd_priv *priv = rsnd_mod_to_priv(cmd_mod);
    214	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
    215	struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
    216	int id = rsnd_mod_id(cmd_mod);
    217	int shift = (id % 2) ? 16 : 0;
    218	u32 mask, val;
    219
    220	rsnd_adg_get_timesel_ratio(priv, io,
    221				   rsnd_src_get_in_rate(priv, io),
    222				   rsnd_src_get_out_rate(priv, io),
    223				   NULL, &val, NULL);
    224
    225	val  = val	<< shift;
    226	mask = 0x0f1f	<< shift;
    227
    228	rsnd_mod_bset(adg_mod, CMDOUT_TIMSEL, mask, val);
    229
    230	return 0;
    231}
    232
    233int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
    234				  struct rsnd_dai_stream *io,
    235				  unsigned int in_rate,
    236				  unsigned int out_rate)
    237{
    238	struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod);
    239	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
    240	struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
    241	u32 in, out;
    242	u32 mask, en;
    243	int id = rsnd_mod_id(src_mod);
    244	int shift = (id % 2) ? 16 : 0;
    245
    246	rsnd_mod_confirm_src(src_mod);
    247
    248	rsnd_adg_get_timesel_ratio(priv, io,
    249				   in_rate, out_rate,
    250				   &in, &out, &en);
    251
    252	in   = in	<< shift;
    253	out  = out	<< shift;
    254	mask = 0x0f1f	<< shift;
    255
    256	rsnd_mod_bset(adg_mod, SRCIN_TIMSEL(id / 2),  mask, in);
    257	rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL(id / 2), mask, out);
    258
    259	if (en)
    260		rsnd_mod_bset(adg_mod, DIV_EN, en, en);
    261
    262	return 0;
    263}
    264
    265static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
    266{
    267	struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
    268	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
    269	struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
    270	struct device *dev = rsnd_priv_to_dev(priv);
    271	int id = rsnd_mod_id(ssi_mod);
    272	int shift = (id % 4) * 8;
    273	u32 mask = 0xFF << shift;
    274
    275	rsnd_mod_confirm_ssi(ssi_mod);
    276
    277	val = val << shift;
    278
    279	/*
    280	 * SSI 8 is not connected to ADG.
    281	 * it works with SSI 7
    282	 */
    283	if (id == 8)
    284		return;
    285
    286	rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL(id / 4), mask, val);
    287
    288	dev_dbg(dev, "AUDIO_CLK_SEL is 0x%x\n", val);
    289}
    290
    291int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate)
    292{
    293	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
    294	int i;
    295	int sel_table[] = {
    296		[CLKA] = 0x1,
    297		[CLKB] = 0x2,
    298		[CLKC] = 0x3,
    299		[CLKI] = 0x0,
    300	};
    301
    302	/*
    303	 * find suitable clock from
    304	 * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
    305	 */
    306	for (i = 0; i < CLKMAX; i++)
    307		if (rate == adg->clk_rate[i])
    308			return sel_table[i];
    309
    310	/*
    311	 * find divided clock from BRGA/BRGB
    312	 */
    313	if (rate == adg->rbga_rate_for_441khz)
    314		return 0x10;
    315
    316	if (rate == adg->rbgb_rate_for_48khz)
    317		return 0x20;
    318
    319	return -EIO;
    320}
    321
    322int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod)
    323{
    324	rsnd_adg_set_ssi_clk(ssi_mod, 0);
    325
    326	return 0;
    327}
    328
    329int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
    330{
    331	struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
    332	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
    333	struct device *dev = rsnd_priv_to_dev(priv);
    334	struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
    335	int data;
    336	u32 ckr = 0;
    337
    338	data = rsnd_adg_clk_query(priv, rate);
    339	if (data < 0)
    340		return data;
    341
    342	rsnd_adg_set_ssi_clk(ssi_mod, data);
    343
    344	if (rsnd_flags_has(adg, LRCLK_ASYNC)) {
    345		if (rsnd_flags_has(adg, AUDIO_OUT_48))
    346			ckr = 0x80000000;
    347	} else {
    348		if (0 == (rate % 8000))
    349			ckr = 0x80000000;
    350	}
    351
    352	rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr | ckr);
    353	rsnd_mod_write(adg_mod, BRRA,  adg->rbga);
    354	rsnd_mod_write(adg_mod, BRRB,  adg->rbgb);
    355
    356	dev_dbg(dev, "CLKOUT is based on BRG%c (= %dHz)\n",
    357		(ckr) ? 'B' : 'A',
    358		(ckr) ?	adg->rbgb_rate_for_48khz :
    359			adg->rbga_rate_for_441khz);
    360
    361	return 0;
    362}
    363
    364void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
    365{
    366	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
    367	struct clk *clk;
    368	int i;
    369
    370	for_each_rsnd_clk(clk, adg, i) {
    371		if (enable) {
    372			clk_prepare_enable(clk);
    373
    374			/*
    375			 * We shouldn't use clk_get_rate() under
    376			 * atomic context. Let's keep it when
    377			 * rsnd_adg_clk_enable() was called
    378			 */
    379			adg->clk_rate[i] = clk_get_rate(clk);
    380		} else {
    381			clk_disable_unprepare(clk);
    382		}
    383	}
    384}
    385
    386static struct clk *rsnd_adg_create_null_clk(struct rsnd_priv *priv,
    387					    const char * const name,
    388					    const char *parent)
    389{
    390	struct device *dev = rsnd_priv_to_dev(priv);
    391	struct clk *clk;
    392
    393	clk = clk_register_fixed_rate(dev, name, parent, 0, 0);
    394	if (IS_ERR_OR_NULL(clk)) {
    395		dev_err(dev, "create null clk error\n");
    396		return ERR_CAST(clk);
    397	}
    398
    399	return clk;
    400}
    401
    402static struct clk *rsnd_adg_null_clk_get(struct rsnd_priv *priv)
    403{
    404	struct rsnd_adg *adg = priv->adg;
    405
    406	if (!adg->null_clk) {
    407		static const char * const name = "rsnd_adg_null";
    408
    409		adg->null_clk = rsnd_adg_create_null_clk(priv, name, NULL);
    410	}
    411
    412	return adg->null_clk;
    413}
    414
    415static void rsnd_adg_null_clk_clean(struct rsnd_priv *priv)
    416{
    417	struct rsnd_adg *adg = priv->adg;
    418
    419	if (adg->null_clk)
    420		clk_unregister_fixed_rate(adg->null_clk);
    421}
    422
    423static int rsnd_adg_get_clkin(struct rsnd_priv *priv)
    424{
    425	struct rsnd_adg *adg = priv->adg;
    426	struct device *dev = rsnd_priv_to_dev(priv);
    427	struct clk *clk;
    428	int i;
    429
    430	for (i = 0; i < CLKMAX; i++) {
    431		clk = devm_clk_get(dev, clk_name[i]);
    432
    433		if (IS_ERR_OR_NULL(clk))
    434			clk = rsnd_adg_null_clk_get(priv);
    435		if (IS_ERR_OR_NULL(clk))
    436			goto err;
    437
    438		adg->clk[i] = clk;
    439	}
    440
    441	return 0;
    442
    443err:
    444	dev_err(dev, "adg clock IN get failed\n");
    445
    446	rsnd_adg_null_clk_clean(priv);
    447
    448	return -EIO;
    449}
    450
    451static void rsnd_adg_unregister_clkout(struct rsnd_priv *priv)
    452{
    453	struct rsnd_adg *adg = priv->adg;
    454	struct clk *clk;
    455	int i;
    456
    457	for_each_rsnd_clkout(clk, adg, i)
    458		clk_unregister_fixed_rate(clk);
    459}
    460
    461static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
    462{
    463	struct rsnd_adg *adg = priv->adg;
    464	struct clk *clk;
    465	struct device *dev = rsnd_priv_to_dev(priv);
    466	struct device_node *np = dev->of_node;
    467	struct property *prop;
    468	u32 ckr, rbgx, rbga, rbgb;
    469	u32 rate, div;
    470#define REQ_SIZE 2
    471	u32 req_rate[REQ_SIZE] = {};
    472	uint32_t count = 0;
    473	unsigned long req_48kHz_rate, req_441kHz_rate;
    474	int i, req_size;
    475	const char *parent_clk_name = NULL;
    476	static const char * const clkout_name[] = {
    477		[CLKOUT]  = "audio_clkout",
    478		[CLKOUT1] = "audio_clkout1",
    479		[CLKOUT2] = "audio_clkout2",
    480		[CLKOUT3] = "audio_clkout3",
    481	};
    482	int brg_table[] = {
    483		[CLKA] = 0x0,
    484		[CLKB] = 0x1,
    485		[CLKC] = 0x4,
    486		[CLKI] = 0x2,
    487	};
    488
    489	ckr = 0;
    490	rbga = 2; /* default 1/6 */
    491	rbgb = 2; /* default 1/6 */
    492
    493	/*
    494	 * ADG supports BRRA/BRRB output only
    495	 * this means all clkout0/1/2/3 will be same rate
    496	 */
    497	prop = of_find_property(np, "clock-frequency", NULL);
    498	if (!prop)
    499		goto rsnd_adg_get_clkout_end;
    500
    501	req_size = prop->length / sizeof(u32);
    502	if (req_size > REQ_SIZE) {
    503		dev_err(dev, "too many clock-frequency\n");
    504		return -EINVAL;
    505	}
    506
    507	of_property_read_u32_array(np, "clock-frequency", req_rate, req_size);
    508	req_48kHz_rate = 0;
    509	req_441kHz_rate = 0;
    510	for (i = 0; i < req_size; i++) {
    511		if (0 == (req_rate[i] % 44100))
    512			req_441kHz_rate = req_rate[i];
    513		if (0 == (req_rate[i] % 48000))
    514			req_48kHz_rate = req_rate[i];
    515	}
    516
    517	if (req_rate[0] % 48000 == 0)
    518		rsnd_flags_set(adg, AUDIO_OUT_48);
    519
    520	if (of_get_property(np, "clkout-lr-asynchronous", NULL))
    521		rsnd_flags_set(adg, LRCLK_ASYNC);
    522
    523	/*
    524	 * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
    525	 * have 44.1kHz or 48kHz base clocks for now.
    526	 *
    527	 * SSI itself can divide parent clock by 1/1 - 1/16
    528	 * see
    529	 *	rsnd_adg_ssi_clk_try_start()
    530	 *	rsnd_ssi_master_clk_start()
    531	 */
    532	adg->rbga_rate_for_441khz	= 0;
    533	adg->rbgb_rate_for_48khz	= 0;
    534	for_each_rsnd_clk(clk, adg, i) {
    535		rate = clk_get_rate(clk);
    536
    537		if (0 == rate) /* not used */
    538			continue;
    539
    540		/* RBGA */
    541		if (!adg->rbga_rate_for_441khz && (0 == rate % 44100)) {
    542			div = 6;
    543			if (req_441kHz_rate)
    544				div = rate / req_441kHz_rate;
    545			rbgx = rsnd_adg_calculate_rbgx(div);
    546			if (BRRx_MASK(rbgx) == rbgx) {
    547				rbga = rbgx;
    548				adg->rbga_rate_for_441khz = rate / div;
    549				ckr |= brg_table[i] << 20;
    550				if (req_441kHz_rate &&
    551				    !rsnd_flags_has(adg, AUDIO_OUT_48))
    552					parent_clk_name = __clk_get_name(clk);
    553			}
    554		}
    555
    556		/* RBGB */
    557		if (!adg->rbgb_rate_for_48khz && (0 == rate % 48000)) {
    558			div = 6;
    559			if (req_48kHz_rate)
    560				div = rate / req_48kHz_rate;
    561			rbgx = rsnd_adg_calculate_rbgx(div);
    562			if (BRRx_MASK(rbgx) == rbgx) {
    563				rbgb = rbgx;
    564				adg->rbgb_rate_for_48khz = rate / div;
    565				ckr |= brg_table[i] << 16;
    566				if (req_48kHz_rate &&
    567				    rsnd_flags_has(adg, AUDIO_OUT_48))
    568					parent_clk_name = __clk_get_name(clk);
    569			}
    570		}
    571	}
    572
    573	/*
    574	 * ADG supports BRRA/BRRB output only.
    575	 * this means all clkout0/1/2/3 will be * same rate
    576	 */
    577
    578	of_property_read_u32(np, "#clock-cells", &count);
    579	/*
    580	 * for clkout
    581	 */
    582	if (!count) {
    583		clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT],
    584					      parent_clk_name, 0, req_rate[0]);
    585		if (IS_ERR_OR_NULL(clk))
    586			goto err;
    587
    588		adg->clkout[CLKOUT] = clk;
    589		of_clk_add_provider(np, of_clk_src_simple_get, clk);
    590	}
    591	/*
    592	 * for clkout0/1/2/3
    593	 */
    594	else {
    595		for (i = 0; i < CLKOUTMAX; i++) {
    596			clk = clk_register_fixed_rate(dev, clkout_name[i],
    597						      parent_clk_name, 0,
    598						      req_rate[0]);
    599			if (IS_ERR_OR_NULL(clk))
    600				goto err;
    601
    602			adg->clkout[i] = clk;
    603		}
    604		adg->onecell.clks	= adg->clkout;
    605		adg->onecell.clk_num	= CLKOUTMAX;
    606		of_clk_add_provider(np, of_clk_src_onecell_get,
    607				    &adg->onecell);
    608	}
    609
    610rsnd_adg_get_clkout_end:
    611	adg->ckr = ckr;
    612	adg->rbga = rbga;
    613	adg->rbgb = rbgb;
    614
    615	return 0;
    616
    617err:
    618	dev_err(dev, "adg clock OUT get failed\n");
    619
    620	rsnd_adg_unregister_clkout(priv);
    621
    622	return -EIO;
    623}
    624
    625#if defined(DEBUG) || defined(CONFIG_DEBUG_FS)
    626__printf(3, 4)
    627static void dbg_msg(struct device *dev, struct seq_file *m,
    628				   const char *fmt, ...)
    629{
    630	char msg[128];
    631	va_list args;
    632
    633	va_start(args, fmt);
    634	vsnprintf(msg, sizeof(msg), fmt, args);
    635	va_end(args);
    636
    637	if (m)
    638		seq_puts(m, msg);
    639	else
    640		dev_dbg(dev, "%s", msg);
    641}
    642
    643void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m)
    644{
    645	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
    646	struct device *dev = rsnd_priv_to_dev(priv);
    647	struct clk *clk;
    648	int i;
    649
    650	for_each_rsnd_clk(clk, adg, i)
    651		dbg_msg(dev, m, "%s    : %pa : %ld\n",
    652			clk_name[i], clk, clk_get_rate(clk));
    653
    654	dbg_msg(dev, m, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
    655		adg->ckr, adg->rbga, adg->rbgb);
    656	dbg_msg(dev, m, "BRGA (for 44100 base) = %d\n", adg->rbga_rate_for_441khz);
    657	dbg_msg(dev, m, "BRGB (for 48000 base) = %d\n", adg->rbgb_rate_for_48khz);
    658
    659	/*
    660	 * Actual CLKOUT will be exchanged in rsnd_adg_ssi_clk_try_start()
    661	 * by BRGCKR::BRGCKR_31
    662	 */
    663	for_each_rsnd_clkout(clk, adg, i)
    664		dbg_msg(dev, m, "clkout %d : %pa : %ld\n", i,
    665			clk, clk_get_rate(clk));
    666}
    667#else
    668#define rsnd_adg_clk_dbg_info(priv, m)
    669#endif
    670
    671int rsnd_adg_probe(struct rsnd_priv *priv)
    672{
    673	struct rsnd_adg *adg;
    674	struct device *dev = rsnd_priv_to_dev(priv);
    675	int ret;
    676
    677	adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
    678	if (!adg)
    679		return -ENOMEM;
    680
    681	ret = rsnd_mod_init(priv, &adg->mod, &adg_ops,
    682		      NULL, 0, 0);
    683	if (ret)
    684		return ret;
    685
    686	priv->adg = adg;
    687
    688	ret = rsnd_adg_get_clkin(priv);
    689	if (ret)
    690		return ret;
    691
    692	ret = rsnd_adg_get_clkout(priv);
    693	if (ret)
    694		return ret;
    695
    696	rsnd_adg_clk_enable(priv);
    697	rsnd_adg_clk_dbg_info(priv, NULL);
    698
    699	return 0;
    700}
    701
    702void rsnd_adg_remove(struct rsnd_priv *priv)
    703{
    704	struct device *dev = rsnd_priv_to_dev(priv);
    705	struct device_node *np = dev->of_node;
    706
    707	rsnd_adg_unregister_clkout(priv);
    708
    709	of_clk_del_provider(np);
    710
    711	rsnd_adg_clk_disable(priv);
    712
    713	/* It should be called after rsnd_adg_clk_disable() */
    714	rsnd_adg_null_clk_clean(priv);
    715}