summaryrefslogtreecommitdiff
path: root/sound/soc/sh/rcar/adg.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sh/rcar/adg.c')
-rw-r--r--sound/soc/sh/rcar/adg.c169
1 files changed, 90 insertions, 79 deletions
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index ca1e1281cefa..7bc4421835d7 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -11,7 +11,7 @@
#define CLKB 1
#define CLKC 2
#define CLKI 3
-#define CLKMAX 4
+#define CLKINMAX 4
#define CLKOUT 0
#define CLKOUT1 1
@@ -25,44 +25,56 @@ static struct rsnd_mod_ops adg_ops = {
.name = "adg",
};
+#define ADG_HZ_441 0
+#define ADG_HZ_48 1
+#define ADG_HZ_SIZE 2
+
struct rsnd_adg {
- struct clk *clk[CLKMAX];
+ struct clk *clkin[CLKINMAX];
struct clk *clkout[CLKOUTMAX];
struct clk *null_clk;
struct clk_onecell_data onecell;
struct rsnd_mod mod;
- int clk_rate[CLKMAX];
- u32 flags;
+ int clkin_rate[CLKINMAX];
+ int clkin_size;
+ int clkout_size;
u32 ckr;
u32 rbga;
u32 rbgb;
- int rbga_rate_for_441khz; /* RBGA */
- int rbgb_rate_for_48khz; /* RBGB */
+ int rbg_rate[ADG_HZ_SIZE]; /* RBGA / RBGB */
};
-#define LRCLK_ASYNC (1 << 0)
-#define AUDIO_OUT_48 (1 << 1)
-
-#define for_each_rsnd_clk(pos, adg, i) \
+#define for_each_rsnd_clkin(pos, adg, i) \
for (i = 0; \
- (i < CLKMAX) && \
- ((pos) = adg->clk[i]); \
+ (i < adg->clkin_size) && \
+ ((pos) = adg->clkin[i]); \
i++)
#define for_each_rsnd_clkout(pos, adg, i) \
for (i = 0; \
- (i < CLKOUTMAX) && \
+ (i < adg->clkout_size) && \
((pos) = adg->clkout[i]); \
i++)
#define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
-static const char * const clk_name[] = {
+static const char * const clkin_name_gen4[] = {
+ [CLKA] = "clkin",
+};
+
+static const char * const clkin_name_gen2[] = {
[CLKA] = "clk_a",
[CLKB] = "clk_b",
[CLKC] = "clk_c",
[CLKI] = "clk_i",
};
+static const char * const clkout_name_gen2[] = {
+ [CLKOUT] = "audio_clkout",
+ [CLKOUT1] = "audio_clkout1",
+ [CLKOUT2] = "audio_clkout2",
+ [CLKOUT3] = "audio_clkout3",
+};
+
static u32 rsnd_adg_calculate_rbgx(unsigned long div)
{
int i;
@@ -116,11 +128,11 @@ static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
unsigned int val, en;
unsigned int min, diff;
unsigned int sel_rate[] = {
- adg->clk_rate[CLKA], /* 0000: CLKA */
- adg->clk_rate[CLKB], /* 0001: CLKB */
- adg->clk_rate[CLKC], /* 0010: CLKC */
- adg->rbga_rate_for_441khz, /* 0011: RBGA */
- adg->rbgb_rate_for_48khz, /* 0100: RBGB */
+ adg->clkin_rate[CLKA], /* 0000: CLKA */
+ adg->clkin_rate[CLKB], /* 0001: CLKB */
+ adg->clkin_rate[CLKC], /* 0010: CLKC */
+ adg->rbg_rate[ADG_HZ_441], /* 0011: RBGA */
+ adg->rbg_rate[ADG_HZ_48], /* 0100: RBGB */
};
min = ~0;
@@ -291,6 +303,7 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate)
{
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+ struct clk *clk;
int i;
int sel_table[] = {
[CLKA] = 0x1,
@@ -303,17 +316,17 @@ int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate)
* find suitable clock from
* AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
*/
- for (i = 0; i < CLKMAX; i++)
- if (rate == adg->clk_rate[i])
+ for_each_rsnd_clkin(clk, adg, i)
+ if (rate == adg->clkin_rate[i])
return sel_table[i];
/*
* find divided clock from BRGA/BRGB
*/
- if (rate == adg->rbga_rate_for_441khz)
+ if (rate == adg->rbg_rate[ADG_HZ_441])
return 0x10;
- if (rate == adg->rbgb_rate_for_48khz)
+ if (rate == adg->rbg_rate[ADG_HZ_48])
return 0x20;
return -EIO;
@@ -341,13 +354,8 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
rsnd_adg_set_ssi_clk(ssi_mod, data);
- if (rsnd_flags_has(adg, LRCLK_ASYNC)) {
- if (rsnd_flags_has(adg, AUDIO_OUT_48))
- ckr = 0x80000000;
- } else {
- if (0 == (rate % 8000))
- ckr = 0x80000000;
- }
+ if (0 == (rate % 8000))
+ ckr = 0x80000000; /* BRGB output = 48kHz */
rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr | ckr);
rsnd_mod_write(adg_mod, BRRA, adg->rbga);
@@ -355,8 +363,8 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
dev_dbg(dev, "CLKOUT is based on BRG%c (= %dHz)\n",
(ckr) ? 'B' : 'A',
- (ckr) ? adg->rbgb_rate_for_48khz :
- adg->rbga_rate_for_441khz);
+ (ckr) ? adg->rbg_rate[ADG_HZ_48] :
+ adg->rbg_rate[ADG_HZ_441]);
return 0;
}
@@ -367,7 +375,7 @@ void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
struct clk *clk;
int i;
- for_each_rsnd_clk(clk, adg, i) {
+ for_each_rsnd_clkin(clk, adg, i) {
if (enable) {
clk_prepare_enable(clk);
@@ -376,7 +384,7 @@ void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
* atomic context. Let's keep it when
* rsnd_adg_clk_enable() was called
*/
- adg->clk_rate[i] = clk_get_rate(clk);
+ adg->clkin_rate[i] = clk_get_rate(clk);
} else {
clk_disable_unprepare(clk);
}
@@ -425,19 +433,30 @@ static int rsnd_adg_get_clkin(struct rsnd_priv *priv)
struct rsnd_adg *adg = priv->adg;
struct device *dev = rsnd_priv_to_dev(priv);
struct clk *clk;
+ const char * const *clkin_name;
+ int clkin_size;
int i;
- for (i = 0; i < CLKMAX; i++) {
- clk = devm_clk_get(dev, clk_name[i]);
+ clkin_name = clkin_name_gen2;
+ clkin_size = ARRAY_SIZE(clkin_name_gen2);
+ if (rsnd_is_gen4(priv)) {
+ clkin_name = clkin_name_gen4;
+ clkin_size = ARRAY_SIZE(clkin_name_gen4);
+ }
+
+ for (i = 0; i < clkin_size; i++) {
+ clk = devm_clk_get(dev, clkin_name[i]);
if (IS_ERR_OR_NULL(clk))
clk = rsnd_adg_null_clk_get(priv);
if (IS_ERR_OR_NULL(clk))
goto err;
- adg->clk[i] = clk;
+ adg->clkin[i] = clk;
}
+ adg->clkin_size = clkin_size;
+
return 0;
err:
@@ -467,18 +486,13 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
struct property *prop;
u32 ckr, rbgx, rbga, rbgb;
u32 rate, div;
-#define REQ_SIZE 2
- u32 req_rate[REQ_SIZE] = {};
+ u32 req_rate[ADG_HZ_SIZE] = {};
uint32_t count = 0;
- unsigned long req_48kHz_rate, req_441kHz_rate;
+ unsigned long req_Hz[ADG_HZ_SIZE];
+ int clkout_size;
int i, req_size;
const char *parent_clk_name = NULL;
- static const char * const clkout_name[] = {
- [CLKOUT] = "audio_clkout",
- [CLKOUT1] = "audio_clkout1",
- [CLKOUT2] = "audio_clkout2",
- [CLKOUT3] = "audio_clkout3",
- };
+ const char * const *clkout_name;
int brg_table[] = {
[CLKA] = 0x0,
[CLKB] = 0x1,
@@ -499,27 +513,21 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
goto rsnd_adg_get_clkout_end;
req_size = prop->length / sizeof(u32);
- if (req_size > REQ_SIZE) {
+ if (req_size > ADG_HZ_SIZE) {
dev_err(dev, "too many clock-frequency\n");
return -EINVAL;
}
of_property_read_u32_array(np, "clock-frequency", req_rate, req_size);
- req_48kHz_rate = 0;
- req_441kHz_rate = 0;
+ req_Hz[ADG_HZ_48] = 0;
+ req_Hz[ADG_HZ_441] = 0;
for (i = 0; i < req_size; i++) {
if (0 == (req_rate[i] % 44100))
- req_441kHz_rate = req_rate[i];
+ req_Hz[ADG_HZ_441] = req_rate[i];
if (0 == (req_rate[i] % 48000))
- req_48kHz_rate = req_rate[i];
+ req_Hz[ADG_HZ_48] = req_rate[i];
}
- if (req_rate[0] % 48000 == 0)
- rsnd_flags_set(adg, AUDIO_OUT_48);
-
- if (of_get_property(np, "clkout-lr-asynchronous", NULL))
- rsnd_flags_set(adg, LRCLK_ASYNC);
-
/*
* This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
* have 44.1kHz or 48kHz base clocks for now.
@@ -529,47 +537,48 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
* rsnd_adg_ssi_clk_try_start()
* rsnd_ssi_master_clk_start()
*/
- adg->rbga_rate_for_441khz = 0;
- adg->rbgb_rate_for_48khz = 0;
- for_each_rsnd_clk(clk, adg, i) {
+ for_each_rsnd_clkin(clk, adg, i) {
rate = clk_get_rate(clk);
if (0 == rate) /* not used */
continue;
/* RBGA */
- if (!adg->rbga_rate_for_441khz && (0 == rate % 44100)) {
+ if (!adg->rbg_rate[ADG_HZ_441] && (0 == rate % 44100)) {
div = 6;
- if (req_441kHz_rate)
- div = rate / req_441kHz_rate;
+ if (req_Hz[ADG_HZ_441])
+ div = rate / req_Hz[ADG_HZ_441];
rbgx = rsnd_adg_calculate_rbgx(div);
if (BRRx_MASK(rbgx) == rbgx) {
rbga = rbgx;
- adg->rbga_rate_for_441khz = rate / div;
+ adg->rbg_rate[ADG_HZ_441] = rate / div;
ckr |= brg_table[i] << 20;
- if (req_441kHz_rate &&
- !rsnd_flags_has(adg, AUDIO_OUT_48))
+ if (req_Hz[ADG_HZ_441])
parent_clk_name = __clk_get_name(clk);
}
}
/* RBGB */
- if (!adg->rbgb_rate_for_48khz && (0 == rate % 48000)) {
+ if (!adg->rbg_rate[ADG_HZ_48] && (0 == rate % 48000)) {
div = 6;
- if (req_48kHz_rate)
- div = rate / req_48kHz_rate;
+ if (req_Hz[ADG_HZ_48])
+ div = rate / req_Hz[ADG_HZ_48];
rbgx = rsnd_adg_calculate_rbgx(div);
if (BRRx_MASK(rbgx) == rbgx) {
rbgb = rbgx;
- adg->rbgb_rate_for_48khz = rate / div;
+ adg->rbg_rate[ADG_HZ_48] = rate / div;
ckr |= brg_table[i] << 16;
- if (req_48kHz_rate &&
- rsnd_flags_has(adg, AUDIO_OUT_48))
+ if (req_Hz[ADG_HZ_48])
parent_clk_name = __clk_get_name(clk);
}
}
}
+ clkout_name = clkout_name_gen2;
+ clkout_size = ARRAY_SIZE(clkout_name_gen2);
+ if (rsnd_is_gen4(priv))
+ clkout_size = 1; /* reuse clkout_name_gen2[] */
+
/*
* ADG supports BRRA/BRRB output only.
* this means all clkout0/1/2/3 will be * same rate
@@ -586,13 +595,14 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
goto err;
adg->clkout[CLKOUT] = clk;
+ adg->clkout_size = 1;
of_clk_add_provider(np, of_clk_src_simple_get, clk);
}
/*
* for clkout0/1/2/3
*/
else {
- for (i = 0; i < CLKOUTMAX; i++) {
+ for (i = 0; i < clkout_size; i++) {
clk = clk_register_fixed_rate(dev, clkout_name[i],
parent_clk_name, 0,
req_rate[0]);
@@ -602,7 +612,8 @@ static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
adg->clkout[i] = clk;
}
adg->onecell.clks = adg->clkout;
- adg->onecell.clk_num = CLKOUTMAX;
+ adg->onecell.clk_num = clkout_size;
+ adg->clkout_size = clkout_size;
of_clk_add_provider(np, of_clk_src_onecell_get,
&adg->onecell);
}
@@ -647,22 +658,22 @@ void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m)
struct clk *clk;
int i;
- for_each_rsnd_clk(clk, adg, i)
+ for_each_rsnd_clkin(clk, adg, i)
dbg_msg(dev, m, "%-18s : %pa : %ld\n",
__clk_get_name(clk), clk, clk_get_rate(clk));
dbg_msg(dev, m, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
adg->ckr, adg->rbga, adg->rbgb);
- dbg_msg(dev, m, "BRGA (for 44100 base) = %d\n", adg->rbga_rate_for_441khz);
- dbg_msg(dev, m, "BRGB (for 48000 base) = %d\n", adg->rbgb_rate_for_48khz);
+ dbg_msg(dev, m, "BRGA (for 44100 base) = %d\n", adg->rbg_rate[ADG_HZ_441]);
+ dbg_msg(dev, m, "BRGB (for 48000 base) = %d\n", adg->rbg_rate[ADG_HZ_48]);
/*
* Actual CLKOUT will be exchanged in rsnd_adg_ssi_clk_try_start()
* by BRGCKR::BRGCKR_31
*/
for_each_rsnd_clkout(clk, adg, i)
- dbg_msg(dev, m, "clkout %d : %pa : %ld\n", i,
- clk, clk_get_rate(clk));
+ dbg_msg(dev, m, "%-18s : %pa : %ld\n",
+ __clk_get_name(clk), clk, clk_get_rate(clk));
}
#else
#define rsnd_adg_clk_dbg_info(priv, m)