From bd4cee2fdf69b56c2bf3e7ec7c2e12b81e08005c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 23:50:31 +0000 Subject: ASoC: rsnd: enable clk_i approximate rate usage Basically Renesas sound ADG is assuming that it has accurately divisible input clock. But sometimes / some board might not have it. The clk_i from CPG is used for such case. It can't calculate accurate division, but can be used as approximate rate. This patch enable clk_i for such case. Signed-off-by: Kuninori Morimoto Acked-by: Adnan Ali Tested-by: Vincenzo De Michele Tested-by: Patrick Keil Link: https://lore.kernel.org/r/87msyizlfd.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 0b8926600d90..c490d43aa18c 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -491,6 +491,7 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) unsigned long req_Hz[ADG_HZ_SIZE]; int clkout_size; int i, req_size; + int approximate = 0; const char *parent_clk_name = NULL; const char * const *clkout_name; int brg_table[] = { @@ -537,6 +538,26 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) * rsnd_adg_ssi_clk_try_start() * rsnd_ssi_master_clk_start() */ + + /* + * [APPROXIMATE] + * + * clk_i (internal clock) can't create accurate rate, it will be approximate rate. + * + * + * + * clk_i needs x2 of required maximum rate. + * see + * - Minimum division of BRRA/BRRB + * - rsnd_ssi_clk_query() + * + * Sample Settings for TDM 8ch, 32bit width + * + * 8(ch) x 32(bit) x 44100(Hz) x 2 = 22579200 + * 8(ch) x 32(bit) x 48000(Hz) x 2 = 24576000 + * + * clock-frequency = <22579200 24576000>; + */ for_each_rsnd_clkin(clk, adg, i) { rate = clk_get_rate(clk); @@ -544,6 +565,10 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) continue; /* BRGA */ + + if (i == CLKI) + /* see [APPROXIMATE] */ + rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_441]) * req_Hz[ADG_HZ_441]; if (!adg->brg_rate[ADG_HZ_441] && (0 == rate % 44100)) { div = 6; if (req_Hz[ADG_HZ_441]) @@ -555,10 +580,16 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) ckr |= brg_table[i] << 20; if (req_Hz[ADG_HZ_441]) parent_clk_name = __clk_get_name(clk); + if (i == CLKI) + approximate = 1; } } /* BRGB */ + + if (i == CLKI) + /* see [APPROXIMATE] */ + rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_48]) * req_Hz[ADG_HZ_48]; if (!adg->brg_rate[ADG_HZ_48] && (0 == rate % 48000)) { div = 6; if (req_Hz[ADG_HZ_48]) @@ -570,10 +601,15 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) ckr |= brg_table[i] << 16; if (req_Hz[ADG_HZ_48]) parent_clk_name = __clk_get_name(clk); + if (i == CLKI) + approximate = 1; } } } + if (approximate) + dev_info(dev, "It uses CLK_I as approximate rate"); + clkout_name = clkout_name_gen2; clkout_size = ARRAY_SIZE(clkout_name_gen2); if (rsnd_is_gen4(priv)) -- cgit v1.2.3 From d059cd40aea6deae716bc6588f24e7b6b421f822 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 23:50:36 +0000 Subject: ASoC: rsnd: setup clock-out only when all conditions are right Current adg.c doesn't assume that requested clock out divide condition doesn't match. In such case, it will indicate strange message, and will register NULL clock, etc. It is just a DT setting miss, but is confusable. This patch check all conditions for it. Reported-by: Vincenzo De Michele Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87lee2zlf7.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index c490d43aa18c..919339b75a25 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -607,6 +607,10 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) } } + if (!(adg->brg_rate[ADG_HZ_48] && req_Hz[ADG_HZ_48]) && + !(adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441])) + goto rsnd_adg_get_clkout_end; + if (approximate) dev_info(dev, "It uses CLK_I as approximate rate"); -- cgit v1.2.3 From 80d4984f38631b1157dd51214ccd3d2fc6d56fbb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 23:50:48 +0000 Subject: ASoC: rsnd: tidyup brga/brgb default value default value for brga/brgb should be 0xff instead of 0x2. This patch tidyup it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87jztmzlew.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 919339b75a25..4acfb92e44f3 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -502,8 +502,8 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) }; ckr = 0; - brga = 2; /* default 1/6 */ - brgb = 2; /* default 1/6 */ + brga = 0xff; /* default */ + brgb = 0xff; /* default */ /* * ADG supports BRRA/BRRB output only -- cgit v1.2.3 From ab0233747f9cf6ba6c6d0c60c1e0e2533db00302 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 23:50:54 +0000 Subject: ASoC: rsnd: remove default division of clock out Current adg has default division for BRRA/BRRB, but it was created at very beginning of the driver implementation, and is now an unnecessary settings. Because it has this default division, unexpected clockout might be selected. For example if it requests only 44.1kHz base clockout, unrequested 48kHz base clockout also will be selected. This patch remove default division of clock out Reported-by: Vincenzo De Michele Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87il96zlep.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 4acfb92e44f3..25d3316a50d1 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -485,7 +485,6 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) struct device_node *np = dev->of_node; struct property *prop; u32 ckr, brgx, brga, brgb; - u32 rate, div; u32 req_rate[ADG_HZ_SIZE] = {}; uint32_t count = 0; unsigned long req_Hz[ADG_HZ_SIZE]; @@ -559,6 +558,8 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) * clock-frequency = <22579200 24576000>; */ for_each_rsnd_clkin(clk, adg, i) { + u32 rate, div; + rate = clk_get_rate(clk); if (0 == rate) /* not used */ @@ -569,10 +570,8 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) if (i == CLKI) /* see [APPROXIMATE] */ rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_441]) * req_Hz[ADG_HZ_441]; - if (!adg->brg_rate[ADG_HZ_441] && (0 == rate % 44100)) { - div = 6; - if (req_Hz[ADG_HZ_441]) - div = rate / req_Hz[ADG_HZ_441]; + if (!adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441] && (0 == rate % 44100)) { + div = rate / req_Hz[ADG_HZ_441]; brgx = rsnd_adg_calculate_brgx(div); if (BRRx_MASK(brgx) == brgx) { brga = brgx; @@ -590,10 +589,8 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv) if (i == CLKI) /* see [APPROXIMATE] */ rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_48]) * req_Hz[ADG_HZ_48]; - if (!adg->brg_rate[ADG_HZ_48] && (0 == rate % 48000)) { - div = 6; - if (req_Hz[ADG_HZ_48]) - div = rate / req_Hz[ADG_HZ_48]; + if (!adg->brg_rate[ADG_HZ_48] && req_Hz[ADG_HZ_48] && (0 == rate % 48000)) { + div = rate / req_Hz[ADG_HZ_48]; brgx = rsnd_adg_calculate_brgx(div); if (BRRx_MASK(brgx) == brgx) { brgb = brgx; -- cgit v1.2.3 From 4acdf9aedd5624aae9335d70a9324d5aaec4034d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 22 Aug 2023 23:51:02 +0000 Subject: ASoC: rsnd: setup BRGCKR/BRRA/BRRB on rsnd_adg_clk_control() Current adg.c will configure BRGCKR/BRRA/BRRB to output clock when it start sound. OTAH, rsnd_adg_clk_enable() will enables clk_a/b/c when driver was probed. But it is strange, these should be set in the same time. This patch fixup it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87h6oqzlei.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 25d3316a50d1..230c48648af3 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -358,8 +358,6 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) ckr = 0x80000000; /* BRGB output = 48kHz */ rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr | ckr); - rsnd_mod_write(adg_mod, BRRA, adg->brga); - rsnd_mod_write(adg_mod, BRRB, adg->brgb); dev_dbg(dev, "CLKOUT is based on BRG%c (= %dHz)\n", (ckr) ? 'B' : 'A', @@ -372,9 +370,16 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) { struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct rsnd_mod *adg_mod = rsnd_mod_get(adg); struct clk *clk; int i; + if (enable) { + rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr); + rsnd_mod_write(adg_mod, BRRA, adg->brga); + rsnd_mod_write(adg_mod, BRRB, adg->brgb); + } + for_each_rsnd_clkin(clk, adg, i) { if (enable) { clk_prepare_enable(clk); -- cgit v1.2.3