diff options
Diffstat (limited to 'sound/soc/sh/rcar/adg.c')
-rw-r--r-- | sound/soc/sh/rcar/adg.c | 169 |
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) |