diff options
Diffstat (limited to 'sound/soc/sh/rcar')
-rw-r--r-- | sound/soc/sh/rcar/Makefile | 3 | ||||
-rw-r--r-- | sound/soc/sh/rcar/adg.c | 775 | ||||
-rw-r--r-- | sound/soc/sh/rcar/cmd.c | 195 | ||||
-rw-r--r-- | sound/soc/sh/rcar/core.c | 2114 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ctu.c | 393 | ||||
-rw-r--r-- | sound/soc/sh/rcar/debugfs.c | 96 | ||||
-rw-r--r-- | sound/soc/sh/rcar/dma.c | 946 | ||||
-rw-r--r-- | sound/soc/sh/rcar/dvc.c | 396 | ||||
-rw-r--r-- | sound/soc/sh/rcar/gen.c | 562 | ||||
-rw-r--r-- | sound/soc/sh/rcar/mix.c | 360 | ||||
-rw-r--r-- | sound/soc/sh/rcar/rsnd.h | 916 | ||||
-rw-r--r-- | sound/soc/sh/rcar/src.c | 736 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ssi.c | 1260 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ssiu.c | 609 |
14 files changed, 0 insertions, 9361 deletions
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile deleted file mode 100644 index d07eccfa3ac2..000000000000 --- a/sound/soc/sh/rcar/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o debugfs.o -obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c deleted file mode 100644 index afd69c6eb654..000000000000 --- a/sound/soc/sh/rcar/adg.c +++ /dev/null @@ -1,775 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Helper routines for R-Car sound ADG. -// -// Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> -#include <linux/clk-provider.h> -#include <linux/clkdev.h> -#include "rsnd.h" - -#define CLKA 0 -#define CLKB 1 -#define CLKC 2 -#define CLKI 3 -#define CLKINMAX 4 - -#define CLKOUT 0 -#define CLKOUT1 1 -#define CLKOUT2 2 -#define CLKOUT3 3 -#define CLKOUTMAX 4 - -#define BRRx_MASK(x) (0x3FF & x) - -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 *clkin[CLKINMAX]; - struct clk *clkout[CLKOUTMAX]; - struct clk *null_clk; - struct clk_onecell_data onecell; - struct rsnd_mod mod; - int clkin_rate[CLKINMAX]; - int clkin_size; - int clkout_size; - u32 ckr; - u32 brga; - u32 brgb; - - int brg_rate[ADG_HZ_SIZE]; /* BRGA / BRGB */ -}; - -#define for_each_rsnd_clkin(pos, adg, i) \ - for (i = 0; \ - (i < adg->clkin_size) && \ - ((pos) = adg->clkin[i]); \ - i++) -#define for_each_rsnd_clkout(pos, adg, i) \ - for (i = 0; \ - (i < adg->clkout_size) && \ - ((pos) = adg->clkout[i]); \ - i++) -#define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg) - -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_brgx(unsigned long div) -{ - int i; - - if (!div) - return 0; - - for (i = 3; i >= 0; i--) { - int ratio = 2 << (i * 2); - if (0 == (div % ratio)) - return (u32)((i << 8) | ((div / ratio) - 1)); - } - - return ~0; -} - -static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io) -{ - struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); - int id = rsnd_mod_id(ssi_mod); - int ws = id; - - if (rsnd_ssi_is_pin_sharing(io)) { - switch (id) { - case 1: - case 2: - case 9: - ws = 0; - break; - case 4: - ws = 3; - break; - case 8: - ws = 7; - break; - } - } else { - /* - * SSI8 is not connected to ADG. - * Thus SSI9 is using ws = 8 - */ - if (id == 9) - ws = 8; - } - - return (0x6 + ws) << 8; -} - -static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv, - struct rsnd_dai_stream *io, - unsigned int target_rate, - unsigned int *target_val, - unsigned int *target_en) -{ - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct device *dev = rsnd_priv_to_dev(priv); - int sel; - unsigned int val, en; - unsigned int min, diff; - unsigned int sel_rate[] = { - adg->clkin_rate[CLKA], /* 0000: CLKA */ - adg->clkin_rate[CLKB], /* 0001: CLKB */ - adg->clkin_rate[CLKC], /* 0010: CLKC */ - adg->brg_rate[ADG_HZ_441], /* 0011: BRGA */ - adg->brg_rate[ADG_HZ_48], /* 0100: BRGB */ - }; - - min = ~0; - val = 0; - en = 0; - for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) { - int idx = 0; - int step = 2; - int div; - - if (!sel_rate[sel]) - continue; - - for (div = 2; div <= 98304; div += step) { - diff = abs(target_rate - sel_rate[sel] / div); - if (min > diff) { - val = (sel << 8) | idx; - min = diff; - en = 1 << (sel + 1); /* fixme */ - } - - /* - * step of 0_0000 / 0_0001 / 0_1101 - * are out of order - */ - if ((idx > 2) && (idx % 2)) - step *= 2; - if (idx == 0x1c) { - div += step; - step *= 2; - } - idx++; - } - } - - if (min == ~0) { - dev_err(dev, "no Input clock\n"); - return; - } - - *target_val = val; - if (target_en) - *target_en = en; -} - -static void rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv, - struct rsnd_dai_stream *io, - unsigned int in_rate, - unsigned int out_rate, - u32 *in, u32 *out, u32 *en) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - unsigned int target_rate; - u32 *target_val; - u32 _in; - u32 _out; - u32 _en; - - /* default = SSI WS */ - _in = - _out = rsnd_adg_ssi_ws_timing_gen2(io); - - target_rate = 0; - target_val = NULL; - _en = 0; - if (runtime->rate != in_rate) { - target_rate = out_rate; - target_val = &_out; - } else if (runtime->rate != out_rate) { - target_rate = in_rate; - target_val = &_in; - } - - if (target_rate) - __rsnd_adg_get_timesel_ratio(priv, io, - target_rate, - target_val, &_en); - - if (in) - *in = _in; - if (out) - *out = _out; - if (en) - *en = _en; -} - -int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(cmd_mod); - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct rsnd_mod *adg_mod = rsnd_mod_get(adg); - int id = rsnd_mod_id(cmd_mod); - int shift = (id % 2) ? 16 : 0; - u32 mask, val; - - rsnd_adg_get_timesel_ratio(priv, io, - rsnd_src_get_in_rate(priv, io), - rsnd_src_get_out_rate(priv, io), - NULL, &val, NULL); - - val = val << shift; - mask = 0x0f1f << shift; - - rsnd_mod_bset(adg_mod, CMDOUT_TIMSEL, mask, val); - - return 0; -} - -int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod, - struct rsnd_dai_stream *io, - unsigned int in_rate, - unsigned int out_rate) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod); - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct rsnd_mod *adg_mod = rsnd_mod_get(adg); - u32 in, out; - u32 mask, en; - int id = rsnd_mod_id(src_mod); - int shift = (id % 2) ? 16 : 0; - - rsnd_mod_confirm_src(src_mod); - - rsnd_adg_get_timesel_ratio(priv, io, - in_rate, out_rate, - &in, &out, &en); - - in = in << shift; - out = out << shift; - mask = 0x0f1f << shift; - - rsnd_mod_bset(adg_mod, SRCIN_TIMSEL(id / 2), mask, in); - rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL(id / 2), mask, out); - - if (en) - rsnd_mod_bset(adg_mod, DIV_EN, en, en); - - return 0; -} - -static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct rsnd_mod *adg_mod = rsnd_mod_get(adg); - struct device *dev = rsnd_priv_to_dev(priv); - int id = rsnd_mod_id(ssi_mod); - int shift = (id % 4) * 8; - u32 mask = 0xFF << shift; - - rsnd_mod_confirm_ssi(ssi_mod); - - val = val << shift; - - /* - * SSI 8 is not connected to ADG. - * it works with SSI 7 - */ - if (id == 8) - return; - - rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL(id / 4), mask, val); - - dev_dbg(dev, "AUDIO_CLK_SEL is 0x%x\n", 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, - [CLKB] = 0x2, - [CLKC] = 0x3, - [CLKI] = 0x0, - }; - - /* - * find suitable clock from - * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI. - */ - 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->brg_rate[ADG_HZ_441]) - return 0x10; - - if (rate == adg->brg_rate[ADG_HZ_48]) - return 0x20; - - return -EIO; -} - -int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod) -{ - rsnd_adg_set_ssi_clk(ssi_mod, 0); - - return 0; -} - -int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_mod *adg_mod = rsnd_mod_get(adg); - int data; - u32 ckr = 0; - - data = rsnd_adg_clk_query(priv, rate); - if (data < 0) - return data; - - rsnd_adg_set_ssi_clk(ssi_mod, data); - - if (0 == (rate % 8000)) - ckr = 0x80000000; /* BRGB output = 48kHz */ - - rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr | ckr); - - dev_dbg(dev, "CLKOUT is based on BRG%c (= %dHz)\n", - (ckr) ? 'B' : 'A', - (ckr) ? adg->brg_rate[ADG_HZ_48] : - adg->brg_rate[ADG_HZ_441]); - - return 0; -} - -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); - - /* - * We shouldn't use clk_get_rate() under - * atomic context. Let's keep it when - * rsnd_adg_clk_enable() was called - */ - adg->clkin_rate[i] = clk_get_rate(clk); - } else { - clk_disable_unprepare(clk); - } - } -} - -static struct clk *rsnd_adg_create_null_clk(struct rsnd_priv *priv, - const char * const name, - const char *parent) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct clk *clk; - - clk = clk_register_fixed_rate(dev, name, parent, 0, 0); - if (IS_ERR_OR_NULL(clk)) { - dev_err(dev, "create null clk error\n"); - return ERR_CAST(clk); - } - - return clk; -} - -static struct clk *rsnd_adg_null_clk_get(struct rsnd_priv *priv) -{ - struct rsnd_adg *adg = priv->adg; - - if (!adg->null_clk) { - static const char * const name = "rsnd_adg_null"; - - adg->null_clk = rsnd_adg_create_null_clk(priv, name, NULL); - } - - return adg->null_clk; -} - -static void rsnd_adg_null_clk_clean(struct rsnd_priv *priv) -{ - struct rsnd_adg *adg = priv->adg; - - if (adg->null_clk) - clk_unregister_fixed_rate(adg->null_clk); -} - -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; - - 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->clkin[i] = clk; - } - - adg->clkin_size = clkin_size; - - return 0; - -err: - dev_err(dev, "adg clock IN get failed\n"); - - rsnd_adg_null_clk_clean(priv); - - return -EIO; -} - -static void rsnd_adg_unregister_clkout(struct rsnd_priv *priv) -{ - struct rsnd_adg *adg = priv->adg; - struct clk *clk; - int i; - - for_each_rsnd_clkout(clk, adg, i) - clk_unregister_fixed_rate(clk); -} - -static int rsnd_adg_get_clkout(struct rsnd_priv *priv) -{ - struct rsnd_adg *adg = priv->adg; - struct clk *clk; - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *np = dev->of_node; - struct property *prop; - u32 ckr, brgx, brga, brgb; - u32 req_rate[ADG_HZ_SIZE] = {}; - uint32_t count = 0; - 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[] = { - [CLKA] = 0x0, - [CLKB] = 0x1, - [CLKC] = 0x4, - [CLKI] = 0x2, - }; - - ckr = 0; - brga = 0xff; /* default */ - brgb = 0xff; /* default */ - - /* - * ADG supports BRRA/BRRB output only - * this means all clkout0/1/2/3 will be same rate - */ - prop = of_find_property(np, "clock-frequency", NULL); - if (!prop) - goto rsnd_adg_get_clkout_end; - - req_size = prop->length / sizeof(u32); - 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_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_Hz[ADG_HZ_441] = req_rate[i]; - if (0 == (req_rate[i] % 48000)) - req_Hz[ADG_HZ_48] = req_rate[i]; - } - - /* - * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC - * have 44.1kHz or 48kHz base clocks for now. - * - * SSI itself can divide parent clock by 1/1 - 1/16 - * see - * 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. - * - * <Note> - * - * 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<Note> = 22579200 - * 8(ch) x 32(bit) x 48000(Hz) x 2<Note> = 24576000 - * - * clock-frequency = <22579200 24576000>; - */ - for_each_rsnd_clkin(clk, adg, i) { - u32 rate, div; - - rate = clk_get_rate(clk); - - if (0 == rate) /* not used */ - 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] && 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; - adg->brg_rate[ADG_HZ_441] = rate / div; - 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] && 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; - adg->brg_rate[ADG_HZ_48] = rate / div; - ckr |= brg_table[i] << 16; - if (req_Hz[ADG_HZ_48]) - parent_clk_name = __clk_get_name(clk); - if (i == CLKI) - approximate = 1; - } - } - } - - 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"); - - 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 - */ - - of_property_read_u32(np, "#clock-cells", &count); - /* - * for clkout - */ - if (!count) { - clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT], - parent_clk_name, 0, req_rate[0]); - if (IS_ERR_OR_NULL(clk)) - 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 < clkout_size; i++) { - clk = clk_register_fixed_rate(dev, clkout_name[i], - parent_clk_name, 0, - req_rate[0]); - if (IS_ERR_OR_NULL(clk)) - goto err; - - adg->clkout[i] = clk; - } - adg->onecell.clks = adg->clkout; - adg->onecell.clk_num = clkout_size; - adg->clkout_size = clkout_size; - of_clk_add_provider(np, of_clk_src_onecell_get, - &adg->onecell); - } - -rsnd_adg_get_clkout_end: - adg->ckr = ckr; - adg->brga = brga; - adg->brgb = brgb; - - return 0; - -err: - dev_err(dev, "adg clock OUT get failed\n"); - - rsnd_adg_unregister_clkout(priv); - - return -EIO; -} - -#if defined(DEBUG) || defined(CONFIG_DEBUG_FS) -__printf(3, 4) -static void dbg_msg(struct device *dev, struct seq_file *m, - const char *fmt, ...) -{ - char msg[128]; - va_list args; - - va_start(args, fmt); - vsnprintf(msg, sizeof(msg), fmt, args); - va_end(args); - - if (m) - seq_puts(m, msg); - else - dev_dbg(dev, "%s", msg); -} - -void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m) -{ - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct device *dev = rsnd_priv_to_dev(priv); - struct clk *clk; - int 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->brga, adg->brgb); - dbg_msg(dev, m, "BRGA (for 44100 base) = %d\n", adg->brg_rate[ADG_HZ_441]); - dbg_msg(dev, m, "BRGB (for 48000 base) = %d\n", adg->brg_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, "%-18s : %pa : %ld\n", - __clk_get_name(clk), clk, clk_get_rate(clk)); -} -#else -#define rsnd_adg_clk_dbg_info(priv, m) -#endif - -int rsnd_adg_probe(struct rsnd_priv *priv) -{ - struct rsnd_adg *adg; - struct device *dev = rsnd_priv_to_dev(priv); - int ret; - - adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL); - if (!adg) - return -ENOMEM; - - ret = rsnd_mod_init(priv, &adg->mod, &adg_ops, - NULL, 0, 0); - if (ret) - return ret; - - priv->adg = adg; - - ret = rsnd_adg_get_clkin(priv); - if (ret) - return ret; - - ret = rsnd_adg_get_clkout(priv); - if (ret) - return ret; - - rsnd_adg_clk_enable(priv); - rsnd_adg_clk_dbg_info(priv, NULL); - - return 0; -} - -void rsnd_adg_remove(struct rsnd_priv *priv) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *np = dev->of_node; - - rsnd_adg_unregister_clkout(priv); - - of_clk_del_provider(np); - - rsnd_adg_clk_disable(priv); - - /* It should be called after rsnd_adg_clk_disable() */ - rsnd_adg_null_clk_clean(priv); -} diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c deleted file mode 100644 index 329e6ab1b222..000000000000 --- a/sound/soc/sh/rcar/cmd.c +++ /dev/null @@ -1,195 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas R-Car CMD support -// -// Copyright (C) 2015 Renesas Solutions Corp. -// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> - -#include "rsnd.h" - -struct rsnd_cmd { - struct rsnd_mod mod; -}; - -#define CMD_NAME "cmd" - -#define rsnd_cmd_nr(priv) ((priv)->cmd_nr) -#define for_each_rsnd_cmd(pos, priv, i) \ - for ((i) = 0; \ - ((i) < rsnd_cmd_nr(priv)) && \ - ((pos) = (struct rsnd_cmd *)(priv)->cmd + i); \ - i++) - -static int rsnd_cmd_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); - struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); - struct device *dev = rsnd_priv_to_dev(priv); - u32 data; - static const u32 path[] = { - [1] = 1 << 0, - [5] = 1 << 8, - [6] = 1 << 12, - [9] = 1 << 15, - }; - - if (!mix && !dvc) - return 0; - - if (ARRAY_SIZE(path) < rsnd_mod_id(mod) + 1) - return -ENXIO; - - if (mix) { - struct rsnd_dai *rdai; - int i; - - /* - * it is assuming that integrater is well understanding about - * data path. Here doesn't check impossible connection, - * like src2 + src5 - */ - data = 0; - for_each_rsnd_dai(rdai, priv, i) { - struct rsnd_dai_stream *tio = &rdai->playback; - struct rsnd_mod *src = rsnd_io_to_mod_src(tio); - - if (mix == rsnd_io_to_mod_mix(tio)) - data |= path[rsnd_mod_id(src)]; - - tio = &rdai->capture; - src = rsnd_io_to_mod_src(tio); - if (mix == rsnd_io_to_mod_mix(tio)) - data |= path[rsnd_mod_id(src)]; - } - - } else { - struct rsnd_mod *src = rsnd_io_to_mod_src(io); - - static const u8 cmd_case[] = { - [0] = 0x3, - [1] = 0x3, - [2] = 0x4, - [3] = 0x1, - [4] = 0x2, - [5] = 0x4, - [6] = 0x1, - [9] = 0x2, - }; - - if (unlikely(!src)) - return -EIO; - - data = path[rsnd_mod_id(src)] | - cmd_case[rsnd_mod_id(src)] << 16; - } - - dev_dbg(dev, "ctu/mix path = 0x%08x\n", data); - - rsnd_mod_write(mod, CMD_ROUTE_SLCT, data); - rsnd_mod_write(mod, CMD_BUSIF_MODE, rsnd_get_busif_shift(io, mod) | 1); - rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); - - rsnd_adg_set_cmd_timsel_gen2(mod, io); - - return 0; -} - -static int rsnd_cmd_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - rsnd_mod_write(mod, CMD_CTRL, 0x10); - - return 0; -} - -static int rsnd_cmd_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - rsnd_mod_write(mod, CMD_CTRL, 0); - - return 0; -} - -#ifdef CONFIG_DEBUG_FS -static void rsnd_cmd_debug_info(struct seq_file *m, - struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, - 0x180 + rsnd_mod_id_raw(mod) * 0x20, 0x30); -} -#define DEBUG_INFO .debug_info = rsnd_cmd_debug_info -#else -#define DEBUG_INFO -#endif - -static struct rsnd_mod_ops rsnd_cmd_ops = { - .name = CMD_NAME, - .init = rsnd_cmd_init, - .start = rsnd_cmd_start, - .stop = rsnd_cmd_stop, - .get_status = rsnd_mod_get_status, - DEBUG_INFO -}; - -static struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id) -{ - if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv))) - id = 0; - - return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id); -} -int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id) -{ - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id); - - return rsnd_dai_connect(mod, io, mod->type); -} - -int rsnd_cmd_probe(struct rsnd_priv *priv) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_cmd *cmd; - int i, nr; - - /* This driver doesn't support Gen1 at this point */ - if (rsnd_is_gen1(priv)) - return 0; - - /* same number as DVC */ - nr = priv->dvc_nr; - if (!nr) - return 0; - - cmd = devm_kcalloc(dev, nr, sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - priv->cmd_nr = nr; - priv->cmd = cmd; - - for_each_rsnd_cmd(cmd, priv, i) { - int ret = rsnd_mod_init(priv, rsnd_mod_get(cmd), - &rsnd_cmd_ops, NULL, - RSND_MOD_CMD, i); - if (ret) - return ret; - } - - return 0; -} - -void rsnd_cmd_remove(struct rsnd_priv *priv) -{ - struct rsnd_cmd *cmd; - int i; - - for_each_rsnd_cmd(cmd, priv, i) { - rsnd_mod_quit(rsnd_mod_get(cmd)); - } -} diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c deleted file mode 100644 index 0b1aa23c1189..000000000000 --- a/sound/soc/sh/rcar/core.c +++ /dev/null @@ -1,2114 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas R-Car SRU/SCU/SSIU/SSI support -// -// Copyright (C) 2013 Renesas Solutions Corp. -// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> -// -// Based on fsi.c -// Kuninori Morimoto <morimoto.kuninori@renesas.com> - -/* - * Renesas R-Car sound device structure - * - * Gen1 - * - * SRU : Sound Routing Unit - * - SRC : Sampling Rate Converter - * - CMD - * - CTU : Channel Count Conversion Unit - * - MIX : Mixer - * - DVC : Digital Volume and Mute Function - * - SSI : Serial Sound Interface - * - * Gen2 - * - * SCU : Sampling Rate Converter Unit - * - SRC : Sampling Rate Converter - * - CMD - * - CTU : Channel Count Conversion Unit - * - MIX : Mixer - * - DVC : Digital Volume and Mute Function - * SSIU : Serial Sound Interface Unit - * - SSI : Serial Sound Interface - */ - -/* - * driver data Image - * - * rsnd_priv - * | - * | ** this depends on Gen1/Gen2 - * | - * +- gen - * | - * | ** these depend on data path - * | ** gen and platform data control it - * | - * +- rdai[0] - * | | sru ssiu ssi - * | +- playback -> [mod] -> [mod] -> [mod] -> ... - * | | - * | | sru ssiu ssi - * | +- capture -> [mod] -> [mod] -> [mod] -> ... - * | - * +- rdai[1] - * | | sru ssiu ssi - * | +- playback -> [mod] -> [mod] -> [mod] -> ... - * | | - * | | sru ssiu ssi - * | +- capture -> [mod] -> [mod] -> [mod] -> ... - * ... - * | - * | ** these control ssi - * | - * +- ssi - * | | - * | +- ssi[0] - * | +- ssi[1] - * | +- ssi[2] - * | ... - * | - * | ** these control src - * | - * +- src - * | - * +- src[0] - * +- src[1] - * +- src[2] - * ... - * - * - * for_each_rsnd_dai(xx, priv, xx) - * rdai[0] => rdai[1] => rdai[2] => ... - * - * for_each_rsnd_mod(xx, rdai, xx) - * [mod] => [mod] => [mod] => ... - * - * rsnd_dai_call(xxx, fn ) - * [mod]->fn() -> [mod]->fn() -> [mod]->fn()... - * - */ - -#include <linux/pm_runtime.h> -#include <linux/of_graph.h> -#include "rsnd.h" - -#define RSND_RATES SNDRV_PCM_RATE_8000_192000 -#define RSND_FMTS (SNDRV_PCM_FMTBIT_S8 |\ - SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S24_LE) - -static const struct of_device_id rsnd_of_match[] = { - { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 }, - { .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 }, - { .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN3 }, - { .compatible = "renesas,rcar_sound-gen4", .data = (void *)RSND_GEN4 }, - /* Special Handling */ - { .compatible = "renesas,rcar_sound-r8a77990", .data = (void *)(RSND_GEN3 | RSND_SOC_E) }, - {}, -}; -MODULE_DEVICE_TABLE(of, rsnd_of_match); - -/* - * rsnd_mod functions - */ -void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type) -{ - if (mod->type != type) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - - dev_warn(dev, "%s is not your expected module\n", - rsnd_mod_name(mod)); - } -} - -struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - if (!mod || !mod->ops || !mod->ops->dma_req) - return NULL; - - return mod->ops->dma_req(io, mod); -} - -#define MOD_NAME_NUM 5 -#define MOD_NAME_SIZE 16 -char *rsnd_mod_name(struct rsnd_mod *mod) -{ - static char names[MOD_NAME_NUM][MOD_NAME_SIZE]; - static int num; - char *name = names[num]; - - num++; - if (num >= MOD_NAME_NUM) - num = 0; - - /* - * Let's use same char to avoid pointlessness memory - * Thus, rsnd_mod_name() should be used immediately - * Don't keep pointer - */ - if ((mod)->ops->id_sub) { - snprintf(name, MOD_NAME_SIZE, "%s[%d%d]", - mod->ops->name, - rsnd_mod_id(mod), - rsnd_mod_id_sub(mod)); - } else { - snprintf(name, MOD_NAME_SIZE, "%s[%d]", - mod->ops->name, - rsnd_mod_id(mod)); - } - - return name; -} - -u32 *rsnd_mod_get_status(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - enum rsnd_mod_type type) -{ - return &mod->status; -} - -int rsnd_mod_id_raw(struct rsnd_mod *mod) -{ - return mod->id; -} - -int rsnd_mod_id(struct rsnd_mod *mod) -{ - if ((mod)->ops->id) - return (mod)->ops->id(mod); - - return rsnd_mod_id_raw(mod); -} - -int rsnd_mod_id_sub(struct rsnd_mod *mod) -{ - if ((mod)->ops->id_sub) - return (mod)->ops->id_sub(mod); - - return 0; -} - -int rsnd_mod_init(struct rsnd_priv *priv, - struct rsnd_mod *mod, - struct rsnd_mod_ops *ops, - struct clk *clk, - enum rsnd_mod_type type, - int id) -{ - int ret = clk_prepare(clk); - - if (ret) - return ret; - - mod->id = id; - mod->ops = ops; - mod->type = type; - mod->clk = clk; - mod->priv = priv; - - return 0; -} - -void rsnd_mod_quit(struct rsnd_mod *mod) -{ - clk_unprepare(mod->clk); - mod->clk = NULL; -} - -void rsnd_mod_interrupt(struct rsnd_mod *mod, - void (*callback)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io)) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_dai *rdai; - int i; - - for_each_rsnd_dai(rdai, priv, i) { - struct rsnd_dai_stream *io = &rdai->playback; - - if (mod == io->mod[mod->type]) - callback(mod, io); - - io = &rdai->capture; - if (mod == io->mod[mod->type]) - callback(mod, io); - } -} - -int rsnd_io_is_working(struct rsnd_dai_stream *io) -{ - /* see rsnd_dai_stream_init/quit() */ - if (io->substream) - return snd_pcm_running(io->substream); - - return 0; -} - -int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, - struct snd_pcm_hw_params *params) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - - /* - * params will be added when refine - * see - * __rsnd_soc_hw_rule_rate() - * __rsnd_soc_hw_rule_channels() - */ - if (params) - return params_channels(params); - else if (runtime) - return runtime->channels; - return 0; -} - -int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, - struct snd_pcm_hw_params *params) -{ - int chan = rsnd_runtime_channel_original_with_params(io, params); - struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io); - - if (ctu_mod) { - u32 converted_chan = rsnd_io_converted_chan(io); - - /* - * !! Note !! - * - * converted_chan will be used for CTU, - * or TDM Split mode. - * User shouldn't use CTU with TDM Split mode. - */ - if (rsnd_runtime_is_tdm_split(io)) { - struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); - - dev_err(dev, "CTU and TDM Split should be used\n"); - } - - if (converted_chan) - return converted_chan; - } - - return chan; -} - -int rsnd_channel_normalization(int chan) -{ - if (WARN_ON((chan > 8) || (chan < 0))) - return 0; - - /* TDM Extend Mode needs 8ch */ - if (chan == 6) - chan = 8; - - return chan; -} - -int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, - struct snd_pcm_hw_params *params) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - int chan = rsnd_io_is_play(io) ? - rsnd_runtime_channel_after_ctu_with_params(io, params) : - rsnd_runtime_channel_original_with_params(io, params); - - /* Use Multi SSI */ - if (rsnd_runtime_is_multi_ssi(io)) - chan /= rsnd_rdai_ssi_lane_get(rdai); - - return rsnd_channel_normalization(chan); -} - -int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - int lane = rsnd_rdai_ssi_lane_get(rdai); - int chan = rsnd_io_is_play(io) ? - rsnd_runtime_channel_after_ctu(io) : - rsnd_runtime_channel_original(io); - - return (chan > 2) && (lane > 1); -} - -int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io) -{ - return rsnd_runtime_channel_for_ssi(io) >= 6; -} - -int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io) -{ - return !!rsnd_flags_has(io, RSND_STREAM_TDM_SPLIT); -} - -/* - * ADINR function - */ -u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct device *dev = rsnd_priv_to_dev(priv); - - switch (snd_pcm_format_width(runtime->format)) { - case 8: - return 16 << 16; - case 16: - return 8 << 16; - case 24: - return 0 << 16; - } - - dev_warn(dev, "not supported sample bits\n"); - - return 0; -} - -/* - * DALIGN function - */ -u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) -{ - static const u32 dalign_values[8] = { - 0x76543210, 0x00000032, 0x00007654, 0x00000076, - 0xfedcba98, 0x000000ba, 0x0000fedc, 0x000000fe, - }; - int id = 0; - struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); - struct rsnd_mod *target; - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - u32 dalign; - - /* - * *Hardware* L/R and *Software* L/R are inverted for 16bit data. - * 31..16 15...0 - * HW: [L ch] [R ch] - * SW: [R ch] [L ch] - * We need to care about inversion timing to control - * Playback/Capture correctly. - * The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R - * - * sL/R : software L/R - * hL/R : hardware L/R - * (*) : conversion timing - * - * Playback - * sL/R (*) hL/R hL/R hL/R hL/R hL/R - * [MEM] -> [SRC] -> [DVC] -> [CMD] -> [SSIU] -> [SSI] -> codec - * - * Capture - * hL/R hL/R hL/R hL/R hL/R (*) sL/R - * codec -> [SSI] -> [SSIU] -> [SRC] -> [DVC] -> [CMD] -> [MEM] - */ - if (rsnd_io_is_play(io)) { - struct rsnd_mod *src = rsnd_io_to_mod_src(io); - - target = src ? src : ssiu; - } else { - struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io); - - target = cmd ? cmd : ssiu; - } - - if (mod == ssiu) - id = rsnd_mod_id_sub(mod); - - dalign = dalign_values[id]; - - if (mod == target && snd_pcm_format_width(runtime->format) == 16) { - /* Target mod needs inverted DALIGN when 16bit */ - dalign = (dalign & 0xf0f0f0f0) >> 4 | - (dalign & 0x0f0f0f0f) << 4; - } - - return dalign; -} - -u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod) -{ - static const enum rsnd_mod_type playback_mods[] = { - RSND_MOD_SRC, - RSND_MOD_CMD, - RSND_MOD_SSIU, - }; - static const enum rsnd_mod_type capture_mods[] = { - RSND_MOD_CMD, - RSND_MOD_SRC, - RSND_MOD_SSIU, - }; - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_mod *tmod = NULL; - const enum rsnd_mod_type *mods = - rsnd_io_is_play(io) ? - playback_mods : capture_mods; - int i; - - /* - * This is needed for 24bit data - * We need to shift 8bit - * - * Linux 24bit data is located as 0x00****** - * HW 24bit data is located as 0x******00 - * - */ - if (snd_pcm_format_width(runtime->format) != 24) - return 0; - - for (i = 0; i < ARRAY_SIZE(playback_mods); i++) { - tmod = rsnd_io_to_mod(io, mods[i]); - if (tmod) - break; - } - - if (tmod != mod) - return 0; - - if (rsnd_io_is_play(io)) - return (0 << 20) | /* shift to Left */ - (8 << 16); /* 8bit */ - else - return (1 << 20) | /* shift to Right */ - (8 << 16); /* 8bit */ -} - -/* - * rsnd_dai functions - */ -struct rsnd_mod *rsnd_mod_next(int *iterator, - struct rsnd_dai_stream *io, - enum rsnd_mod_type *array, - int array_size) -{ - int max = array ? array_size : RSND_MOD_MAX; - - for (; *iterator < max; (*iterator)++) { - enum rsnd_mod_type type = (array) ? array[*iterator] : *iterator; - struct rsnd_mod *mod = rsnd_io_to_mod(io, type); - - if (mod) - return mod; - } - - return NULL; -} - -static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { - { - /* CAPTURE */ - RSND_MOD_AUDMAPP, - RSND_MOD_AUDMA, - RSND_MOD_DVC, - RSND_MOD_MIX, - RSND_MOD_CTU, - RSND_MOD_CMD, - RSND_MOD_SRC, - RSND_MOD_SSIU, - RSND_MOD_SSIM3, - RSND_MOD_SSIM2, - RSND_MOD_SSIM1, - RSND_MOD_SSIP, - RSND_MOD_SSI, - }, { - /* PLAYBACK */ - RSND_MOD_AUDMAPP, - RSND_MOD_AUDMA, - RSND_MOD_SSIM3, - RSND_MOD_SSIM2, - RSND_MOD_SSIM1, - RSND_MOD_SSIP, - RSND_MOD_SSI, - RSND_MOD_SSIU, - RSND_MOD_DVC, - RSND_MOD_MIX, - RSND_MOD_CTU, - RSND_MOD_CMD, - RSND_MOD_SRC, - }, -}; - -static int rsnd_status_update(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, enum rsnd_mod_type type, - int shift, int add, int timing) -{ - u32 *status = mod->ops->get_status(mod, io, type); - u32 mask = 0xF << shift; - u8 val = (*status >> shift) & 0xF; - u8 next_val = (val + add) & 0xF; - int func_call = (val == timing); - - /* no status update */ - if (add == 0 || shift == 28) - return 1; - - if (next_val == 0xF) /* underflow case */ - func_call = -1; - else - *status = (*status & ~mask) + (next_val << shift); - - return func_call; -} - -#define rsnd_dai_call(fn, io, param...) \ -({ \ - struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); \ - struct rsnd_mod *mod; \ - int is_play = rsnd_io_is_play(io); \ - int ret = 0, i; \ - enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \ - for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \ - int tmp = 0; \ - int func_call = rsnd_status_update(io, mod, types[i], \ - __rsnd_mod_shift_##fn, \ - __rsnd_mod_add_##fn, \ - __rsnd_mod_call_##fn); \ - if (func_call > 0 && (mod)->ops->fn) \ - tmp = (mod)->ops->fn(mod, io, param); \ - if (unlikely(func_call < 0) || \ - unlikely(tmp && (tmp != -EPROBE_DEFER))) \ - dev_err(dev, "%s : %s error (%d, %d)\n", \ - rsnd_mod_name(mod), #fn, tmp, func_call);\ - ret |= tmp; \ - } \ - ret; \ -}) - -int rsnd_dai_connect(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - enum rsnd_mod_type type) -{ - struct rsnd_priv *priv; - struct device *dev; - - if (!mod) - return -EIO; - - if (io->mod[type] == mod) - return 0; - - if (io->mod[type]) - return -EINVAL; - - priv = rsnd_mod_to_priv(mod); - dev = rsnd_priv_to_dev(priv); - - io->mod[type] = mod; - - dev_dbg(dev, "%s is connected to io (%s)\n", - rsnd_mod_name(mod), - rsnd_io_is_play(io) ? "Playback" : "Capture"); - - return 0; -} - -static void rsnd_dai_disconnect(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - enum rsnd_mod_type type) -{ - io->mod[type] = NULL; -} - -int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai, - int max_channels) -{ - if (max_channels > 0) - rdai->max_channels = max_channels; - - return rdai->max_channels; -} - -int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, - int ssi_lane) -{ - if (ssi_lane > 0) - rdai->ssi_lane = ssi_lane; - - return rdai->ssi_lane; -} - -int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width) -{ - if (width > 0) - rdai->chan_width = width; - - return rdai->chan_width; -} - -struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id) -{ - if ((id < 0) || (id >= rsnd_rdai_nr(priv))) - return NULL; - - return priv->rdai + id; -} - -static struct snd_soc_dai_driver -*rsnd_daidrv_get(struct rsnd_priv *priv, int id) -{ - if ((id < 0) || (id >= rsnd_rdai_nr(priv))) - return NULL; - - return priv->daidrv + id; -} - -#define rsnd_dai_to_priv(dai) snd_soc_dai_get_drvdata(dai) -static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai) -{ - struct rsnd_priv *priv = rsnd_dai_to_priv(dai); - - return rsnd_rdai_get(priv, dai->id); -} - -/* - * rsnd_soc_dai functions - */ -void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io) -{ - struct snd_pcm_substream *substream = io->substream; - - /* - * this function should be called... - * - * - if rsnd_dai_pointer_update() returns true - * - without spin lock - */ - - snd_pcm_period_elapsed(substream); -} - -static void rsnd_dai_stream_init(struct rsnd_dai_stream *io, - struct snd_pcm_substream *substream) -{ - io->substream = substream; -} - -static void rsnd_dai_stream_quit(struct rsnd_dai_stream *io) -{ - io->substream = NULL; -} - -static -struct snd_soc_dai *rsnd_substream_to_dai(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - - return snd_soc_rtd_to_cpu(rtd, 0); -} - -static -struct rsnd_dai_stream *rsnd_rdai_to_io(struct rsnd_dai *rdai, - struct snd_pcm_substream *substream) -{ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - return &rdai->playback; - else - return &rdai->capture; -} - -static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct rsnd_priv *priv = rsnd_dai_to_priv(dai); - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); - int ret; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - ret = rsnd_dai_call(init, io, priv); - if (ret < 0) - goto dai_trigger_end; - - ret = rsnd_dai_call(start, io, priv); - if (ret < 0) - goto dai_trigger_end; - - ret = rsnd_dai_call(irq, io, priv, 1); - if (ret < 0) - goto dai_trigger_end; - - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - ret = rsnd_dai_call(irq, io, priv, 0); - - ret |= rsnd_dai_call(stop, io, priv); - - ret |= rsnd_dai_call(quit, io, priv); - - break; - default: - ret = -EINVAL; - } - -dai_trigger_end: - spin_unlock_irqrestore(&priv->lock, flags); - - return ret; -} - -static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) -{ - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - - /* set clock master for audio interface */ - switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_BC_FC: - rdai->clk_master = 0; - break; - case SND_SOC_DAIFMT_BP_FP: - rdai->clk_master = 1; /* cpu is master */ - break; - default: - return -EINVAL; - } - - /* set format */ - rdai->bit_clk_inv = 0; - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - rdai->sys_delay = 0; - rdai->data_alignment = 0; - rdai->frm_clk_inv = 0; - break; - case SND_SOC_DAIFMT_LEFT_J: - case SND_SOC_DAIFMT_DSP_B: - rdai->sys_delay = 1; - rdai->data_alignment = 0; - rdai->frm_clk_inv = 1; - break; - case SND_SOC_DAIFMT_RIGHT_J: - rdai->sys_delay = 1; - rdai->data_alignment = 1; - rdai->frm_clk_inv = 1; - break; - case SND_SOC_DAIFMT_DSP_A: - rdai->sys_delay = 0; - rdai->data_alignment = 0; - rdai->frm_clk_inv = 1; - break; - } - - /* set clock inversion */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_IF: - rdai->frm_clk_inv = !rdai->frm_clk_inv; - break; - case SND_SOC_DAIFMT_IB_NF: - rdai->bit_clk_inv = !rdai->bit_clk_inv; - break; - case SND_SOC_DAIFMT_IB_IF: - rdai->bit_clk_inv = !rdai->bit_clk_inv; - rdai->frm_clk_inv = !rdai->frm_clk_inv; - break; - case SND_SOC_DAIFMT_NB_NF: - default: - break; - } - - return 0; -} - -static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, - u32 tx_mask, u32 rx_mask, - int slots, int slot_width) -{ - struct rsnd_priv *priv = rsnd_dai_to_priv(dai); - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct device *dev = rsnd_priv_to_dev(priv); - - switch (slot_width) { - case 16: - case 24: - case 32: - break; - default: - /* use default */ - /* - * Indicate warning if DT has "dai-tdm-slot-width" - * but the value was not expected. - */ - if (slot_width) - dev_warn(dev, "unsupported TDM slot width (%d), force to use default 32\n", - slot_width); - slot_width = 32; - } - - switch (slots) { - case 2: - /* TDM Split Mode */ - case 6: - case 8: - /* TDM Extend Mode */ - rsnd_rdai_channels_set(rdai, slots); - rsnd_rdai_ssi_lane_set(rdai, 1); - rsnd_rdai_width_set(rdai, slot_width); - break; - default: - dev_err(dev, "unsupported TDM slots (%d)\n", slots); - return -EINVAL; - } - - return 0; -} - -static unsigned int rsnd_soc_hw_channels_list[] = { - 2, 6, 8, -}; - -static unsigned int rsnd_soc_hw_rate_list[] = { - 8000, - 11025, - 16000, - 22050, - 32000, - 44100, - 48000, - 64000, - 88200, - 96000, - 176400, - 192000, -}; - -static int rsnd_soc_hw_rule(struct rsnd_dai *rdai, - unsigned int *list, int list_num, - struct snd_interval *baseline, struct snd_interval *iv, - struct rsnd_dai_stream *io, char *unit) -{ - struct snd_interval p; - unsigned int rate; - int i; - - snd_interval_any(&p); - p.min = UINT_MAX; - p.max = 0; - - for (i = 0; i < list_num; i++) { - - if (!snd_interval_test(iv, list[i])) - continue; - - rate = rsnd_ssi_clk_query(rdai, - baseline->min, list[i], NULL); - if (rate > 0) { - p.min = min(p.min, list[i]); - p.max = max(p.max, list[i]); - } - - rate = rsnd_ssi_clk_query(rdai, - baseline->max, list[i], NULL); - if (rate > 0) { - p.min = min(p.min, list[i]); - p.max = max(p.max, list[i]); - } - } - - /* Indicate error once if it can't handle */ - if (!rsnd_flags_has(io, RSND_HW_RULE_ERR) && (p.min > p.max)) { - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); - struct device *dev = rsnd_priv_to_dev(priv); - - dev_warn(dev, "It can't handle %d %s <-> %d %s\n", - baseline->min, unit, baseline->max, unit); - rsnd_flags_set(io, RSND_HW_RULE_ERR); - } - - return snd_interval_refine(iv, &p); -} - -static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval ic; - struct rsnd_dai_stream *io = rule->private; - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - - /* - * possible sampling rate limitation is same as - * 2ch if it supports multi ssi - * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init()) - */ - ic = *ic_; - ic.min = - ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); - - return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_rate_list, - ARRAY_SIZE(rsnd_soc_hw_rate_list), - &ic, ir, io, "ch"); -} - -static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval ic; - struct rsnd_dai_stream *io = rule->private; - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - - /* - * possible sampling rate limitation is same as - * 2ch if it supports multi ssi - * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init()) - */ - ic = *ic_; - ic.min = - ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); - - return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_channels_list, - ARRAY_SIZE(rsnd_soc_hw_channels_list), - ir, &ic, io, "Hz"); -} - -static const struct snd_pcm_hardware rsnd_pcm_hardware = { - .info = SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID, - .buffer_bytes_max = 64 * 1024, - .period_bytes_min = 32, - .period_bytes_max = 8192, - .periods_min = 1, - .periods_max = 32, - .fifo_size = 256, -}; - -static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); - struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint; - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int max_channels = rsnd_rdai_channels_get(rdai); - int i; - - rsnd_flags_del(io, RSND_HW_RULE_ERR); - - rsnd_dai_stream_init(io, substream); - - /* - * Channel Limitation - * It depends on Platform design - */ - constraint->list = rsnd_soc_hw_channels_list; - constraint->count = 0; - constraint->mask = 0; - - for (i = 0; i < ARRAY_SIZE(rsnd_soc_hw_channels_list); i++) { - if (rsnd_soc_hw_channels_list[i] > max_channels) - break; - constraint->count = i + 1; - } - - snd_soc_set_runtime_hwparams(substream, &rsnd_pcm_hardware); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, constraint); - - snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - - /* - * Sampling Rate / Channel Limitation - * It depends on Clock Master Mode - */ - if (rsnd_rdai_is_clk_master(rdai)) { - int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - - snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - rsnd_soc_hw_rule_rate, - is_play ? &rdai->playback : &rdai->capture, - SNDRV_PCM_HW_PARAM_CHANNELS, -1); - snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - rsnd_soc_hw_rule_channels, - is_play ? &rdai->playback : &rdai->capture, - SNDRV_PCM_HW_PARAM_RATE, -1); - } - - return 0; -} - -static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); - struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); - - /* - * call rsnd_dai_call without spinlock - */ - rsnd_dai_call(cleanup, io, priv); - - rsnd_dai_stream_quit(io); -} - -static int rsnd_soc_dai_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct rsnd_priv *priv = rsnd_dai_to_priv(dai); - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); - - return rsnd_dai_call(prepare, io, priv); -} - -static u64 rsnd_soc_dai_formats[] = { - /* - * 1st Priority - * - * Well tested formats. - * Select below from Sound Card, not auto - * SND_SOC_DAIFMT_CBC_CFC - * SND_SOC_DAIFMT_CBP_CFP - */ - SND_SOC_POSSIBLE_DAIFMT_I2S | - SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | - SND_SOC_POSSIBLE_DAIFMT_LEFT_J | - SND_SOC_POSSIBLE_DAIFMT_NB_NF | - SND_SOC_POSSIBLE_DAIFMT_NB_IF | - SND_SOC_POSSIBLE_DAIFMT_IB_NF | - SND_SOC_POSSIBLE_DAIFMT_IB_IF, - /* - * 2nd Priority - * - * Supported, but not well tested - */ - SND_SOC_POSSIBLE_DAIFMT_DSP_A | - SND_SOC_POSSIBLE_DAIFMT_DSP_B, -}; - -static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, - struct rsnd_dai_stream *io, - struct device_node *dai_np) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *ssiu_np = rsnd_ssiu_of_node(priv); - struct device_node *np; - int is_play = rsnd_io_is_play(io); - int i; - - if (!ssiu_np) - return; - - /* - * This driver assumes that it is TDM Split mode - * if it includes ssiu node - */ - for (i = 0;; i++) { - struct device_node *node = is_play ? - of_parse_phandle(dai_np, "playback", i) : - of_parse_phandle(dai_np, "capture", i); - - if (!node) - break; - - for_each_child_of_node(ssiu_np, np) { - if (np == node) { - rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT); - dev_dbg(dev, "%s is part of TDM Split\n", io->name); - } - } - - of_node_put(node); - } - - of_node_put(ssiu_np); -} - -static void rsnd_parse_connect_simple(struct rsnd_priv *priv, - struct rsnd_dai_stream *io, - struct device_node *dai_np) -{ - if (!rsnd_io_to_mod_ssi(io)) - return; - - rsnd_parse_tdm_split_mode(priv, io, dai_np); -} - -static void rsnd_parse_connect_graph(struct rsnd_priv *priv, - struct rsnd_dai_stream *io, - struct device_node *endpoint) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *remote_node; - - if (!rsnd_io_to_mod_ssi(io)) - return; - - remote_node = of_graph_get_remote_port_parent(endpoint); - - /* HDMI0 */ - if (strstr(remote_node->full_name, "hdmi@fead0000")) { - rsnd_flags_set(io, RSND_STREAM_HDMI0); - dev_dbg(dev, "%s connected to HDMI0\n", io->name); - } - - /* HDMI1 */ - if (strstr(remote_node->full_name, "hdmi@feae0000")) { - rsnd_flags_set(io, RSND_STREAM_HDMI1); - dev_dbg(dev, "%s connected to HDMI1\n", io->name); - } - - rsnd_parse_tdm_split_mode(priv, io, endpoint); - - of_node_put(remote_node); -} - -void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name, - struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), - struct device_node *node, - struct device_node *playback, - struct device_node *capture) -{ - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *np; - int i; - - if (!node) - return; - - i = 0; - for_each_child_of_node(node, np) { - struct rsnd_mod *mod; - - i = rsnd_node_fixed_index(dev, np, name, i); - if (i < 0) { - of_node_put(np); - break; - } - - mod = mod_get(priv, i); - - if (np == playback) - rsnd_dai_connect(mod, &rdai->playback, mod->type); - if (np == capture) - rsnd_dai_connect(mod, &rdai->capture, mod->type); - i++; - } - - of_node_put(node); -} - -int rsnd_node_fixed_index(struct device *dev, struct device_node *node, char *name, int idx) -{ - char node_name[16]; - - /* - * rsnd is assuming each device nodes are sequential numbering, - * but some of them are not. - * This function adjusts index for it. - * - * ex) - * Normal case, special case - * ssi-0 - * ssi-1 - * ssi-2 - * ssi-3 ssi-3 - * ssi-4 ssi-4 - * ... - * - * assume Max 64 node - */ - for (; idx < 64; idx++) { - snprintf(node_name, sizeof(node_name), "%s-%d", name, idx); - - if (strncmp(node_name, of_node_full_name(node), sizeof(node_name)) == 0) - return idx; - } - - dev_err(dev, "strange node numbering (%s)", - of_node_full_name(node)); - return -EINVAL; -} - -int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *np; - int i; - - i = 0; - for_each_child_of_node(node, np) { - i = rsnd_node_fixed_index(dev, np, name, i); - if (i < 0) { - of_node_put(np); - return 0; - } - i++; - } - - return i; -} - -static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *np = dev->of_node; - struct device_node *ports, *node; - int nr = 0; - int i = 0; - - *is_graph = 0; - - /* - * parse both previous dai (= rcar_sound,dai), and - * graph dai (= ports/port) - */ - - /* - * Simple-Card - */ - node = of_get_child_by_name(np, RSND_NODE_DAI); - if (!node) - goto audio_graph; - - of_node_put(node); - - for_each_child_of_node(np, node) { - if (!of_node_name_eq(node, RSND_NODE_DAI)) - continue; - - priv->component_dais[i] = of_get_child_count(node); - nr += priv->component_dais[i]; - i++; - if (i >= RSND_MAX_COMPONENT) { - dev_info(dev, "reach to max component\n"); - of_node_put(node); - break; - } - } - - return nr; - -audio_graph: - /* - * Audio-Graph-Card - */ - for_each_child_of_node(np, ports) { - if (!of_node_name_eq(ports, "ports") && - !of_node_name_eq(ports, "port")) - continue; - priv->component_dais[i] = of_graph_get_endpoint_count(ports); - nr += priv->component_dais[i]; - i++; - if (i >= RSND_MAX_COMPONENT) { - dev_info(dev, "reach to max component\n"); - of_node_put(ports); - break; - } - } - - *is_graph = 1; - - return nr; -} - - -#define PREALLOC_BUFFER (32 * 1024) -#define PREALLOC_BUFFER_MAX (32 * 1024) - -static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd, - struct rsnd_dai_stream *io, - int stream) -{ - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct device *dev = rsnd_priv_to_dev(priv); - struct snd_pcm_substream *substream; - - /* - * use Audio-DMAC dev if we can use IPMMU - * see - * rsnd_dmaen_attach() - */ - if (io->dmac_dev) - dev = io->dmac_dev; - - for (substream = rtd->pcm->streams[stream].substream; - substream; - substream = substream->next) { - snd_pcm_set_managed_buffer(substream, - SNDRV_DMA_TYPE_DEV, - dev, - PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); - } - - return 0; -} - -static int rsnd_soc_dai_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) -{ - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - int ret; - - ret = rsnd_dai_call(pcm_new, &rdai->playback, rtd); - if (ret) - return ret; - - ret = rsnd_dai_call(pcm_new, &rdai->capture, rtd); - if (ret) - return ret; - - ret = rsnd_preallocate_pages(rtd, &rdai->playback, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret) - return ret; - - ret = rsnd_preallocate_pages(rtd, &rdai->capture, - SNDRV_PCM_STREAM_CAPTURE); - if (ret) - return ret; - - return 0; -} - -static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { - .pcm_new = rsnd_soc_dai_pcm_new, - .startup = rsnd_soc_dai_startup, - .shutdown = rsnd_soc_dai_shutdown, - .trigger = rsnd_soc_dai_trigger, - .set_fmt = rsnd_soc_dai_set_fmt, - .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, - .prepare = rsnd_soc_dai_prepare, - .auto_selectable_formats = rsnd_soc_dai_formats, - .num_auto_selectable_formats = ARRAY_SIZE(rsnd_soc_dai_formats), -}; - -static void __rsnd_dai_probe(struct rsnd_priv *priv, - struct device_node *dai_np, - struct device_node *node_np, - uint32_t node_arg, - int dai_i) -{ - struct rsnd_dai_stream *io_playback; - struct rsnd_dai_stream *io_capture; - struct snd_soc_dai_driver *drv; - struct rsnd_dai *rdai; - struct device *dev = rsnd_priv_to_dev(priv); - int playback_exist = 0, capture_exist = 0; - int io_i; - - rdai = rsnd_rdai_get(priv, dai_i); - drv = rsnd_daidrv_get(priv, dai_i); - io_playback = &rdai->playback; - io_capture = &rdai->capture; - - snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i); - - /* for multi Component */ - rdai->dai_args.np = node_np; - rdai->dai_args.args_count = 1; - rdai->dai_args.args[0] = node_arg; - - rdai->priv = priv; - drv->name = rdai->name; - drv->ops = &rsnd_soc_dai_ops; - drv->id = dai_i; - drv->dai_args = &rdai->dai_args; - - io_playback->rdai = rdai; - io_capture->rdai = rdai; - rsnd_rdai_channels_set(rdai, 2); /* default 2ch */ - rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */ - rsnd_rdai_width_set(rdai, 32); /* default 32bit width */ - - for (io_i = 0;; io_i++) { - struct device_node *playback = of_parse_phandle(dai_np, "playback", io_i); - struct device_node *capture = of_parse_phandle(dai_np, "capture", io_i); - - if (!playback && !capture) - break; - - if (io_i == 0) { - /* check whether playback/capture property exists */ - if (playback) - playback_exist = 1; - if (capture) - capture_exist = 1; - } - - rsnd_parse_connect_ssi(rdai, playback, capture); - rsnd_parse_connect_ssiu(rdai, playback, capture); - rsnd_parse_connect_src(rdai, playback, capture); - rsnd_parse_connect_ctu(rdai, playback, capture); - rsnd_parse_connect_mix(rdai, playback, capture); - rsnd_parse_connect_dvc(rdai, playback, capture); - - of_node_put(playback); - of_node_put(capture); - } - - if (playback_exist) { - snprintf(io_playback->name, RSND_DAI_NAME_SIZE, "DAI%d Playback", dai_i); - drv->playback.rates = RSND_RATES; - drv->playback.formats = RSND_FMTS; - drv->playback.channels_min = 2; - drv->playback.channels_max = 8; - drv->playback.stream_name = io_playback->name; - } - if (capture_exist) { - snprintf(io_capture->name, RSND_DAI_NAME_SIZE, "DAI%d Capture", dai_i); - drv->capture.rates = RSND_RATES; - drv->capture.formats = RSND_FMTS; - drv->capture.channels_min = 2; - drv->capture.channels_max = 8; - drv->capture.stream_name = io_capture->name; - } - - if (rsnd_ssi_is_pin_sharing(io_capture) || - rsnd_ssi_is_pin_sharing(io_playback)) { - /* should have symmetric_rate if pin sharing */ - drv->symmetric_rate = 1; - } - - dev_dbg(dev, "%s (%s/%s)\n", rdai->name, - rsnd_io_to_mod_ssi(io_playback) ? "play" : " -- ", - rsnd_io_to_mod_ssi(io_capture) ? "capture" : " -- "); -} - -static int rsnd_dai_probe(struct rsnd_priv *priv) -{ - struct snd_soc_dai_driver *rdrv; - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *np = dev->of_node; - struct rsnd_dai *rdai; - int nr = 0; - int is_graph; - int dai_i; - - nr = rsnd_dai_of_node(priv, &is_graph); - if (!nr) - return -EINVAL; - - rdrv = devm_kcalloc(dev, nr, sizeof(*rdrv), GFP_KERNEL); - rdai = devm_kcalloc(dev, nr, sizeof(*rdai), GFP_KERNEL); - if (!rdrv || !rdai) - return -ENOMEM; - - priv->rdai_nr = nr; - priv->daidrv = rdrv; - priv->rdai = rdai; - - /* - * parse all dai - */ - dai_i = 0; - if (is_graph) { - struct device_node *ports; - struct device_node *dai_np; - - for_each_child_of_node(np, ports) { - if (!of_node_name_eq(ports, "ports") && - !of_node_name_eq(ports, "port")) - continue; - for_each_endpoint_of_node(ports, dai_np) { - __rsnd_dai_probe(priv, dai_np, dai_np, 0, dai_i); - if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) { - rdai = rsnd_rdai_get(priv, dai_i); - - rsnd_parse_connect_graph(priv, &rdai->playback, dai_np); - rsnd_parse_connect_graph(priv, &rdai->capture, dai_np); - } - dai_i++; - } - } - } else { - struct device_node *node; - struct device_node *dai_np; - - for_each_child_of_node(np, node) { - if (!of_node_name_eq(node, RSND_NODE_DAI)) - continue; - - for_each_child_of_node(node, dai_np) { - __rsnd_dai_probe(priv, dai_np, np, dai_i, dai_i); - if (rsnd_is_gen3(priv) || rsnd_is_gen4(priv)) { - rdai = rsnd_rdai_get(priv, dai_i); - - rsnd_parse_connect_simple(priv, &rdai->playback, dai_np); - rsnd_parse_connect_simple(priv, &rdai->capture, dai_np); - } - dai_i++; - } - } - } - - return 0; -} - -/* - * pcm ops - */ -static int rsnd_hw_update(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); - struct rsnd_priv *priv = rsnd_io_to_priv(io); - unsigned long flags; - int ret; - - spin_lock_irqsave(&priv->lock, flags); - if (hw_params) - ret = rsnd_dai_call(hw_params, io, substream, hw_params); - else - ret = rsnd_dai_call(hw_free, io, substream); - spin_unlock_irqrestore(&priv->lock, flags); - - return ret; -} - -static int rsnd_hw_params(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); - struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream); - - /* - * rsnd assumes that it might be used under DPCM if user want to use - * channel / rate convert. Then, rsnd should be FE. - * And then, this function will be called *after* BE settings. - * this means, each BE already has fixuped hw_params. - * see - * dpcm_fe_dai_hw_params() - * dpcm_be_dai_hw_params() - */ - io->converted_rate = 0; - io->converted_chan = 0; - if (fe->dai_link->dynamic) { - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct device *dev = rsnd_priv_to_dev(priv); - struct snd_soc_dpcm *dpcm; - int stream = substream->stream; - - for_each_dpcm_be(fe, stream, dpcm) { - struct snd_soc_pcm_runtime *be = dpcm->be; - struct snd_pcm_hw_params *be_params = &be->dpcm[stream].hw_params; - - if (params_channels(hw_params) != params_channels(be_params)) - io->converted_chan = params_channels(be_params); - if (params_rate(hw_params) != params_rate(be_params)) - io->converted_rate = params_rate(be_params); - } - if (io->converted_chan) - dev_dbg(dev, "convert channels = %d\n", io->converted_chan); - if (io->converted_rate) { - /* - * SRC supports convert rates from params_rate(hw_params)/k_down - * to params_rate(hw_params)*k_up, where k_up is always 6, and - * k_down depends on number of channels and SRC unit. - * So all SRC units can upsample audio up to 6 times regardless - * its number of channels. And all SRC units can downsample - * 2 channel audio up to 6 times too. - */ - int k_up = 6; - int k_down = 6; - int channel; - struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); - - dev_dbg(dev, "convert rate = %d\n", io->converted_rate); - - channel = io->converted_chan ? io->converted_chan : - params_channels(hw_params); - - switch (rsnd_mod_id(src_mod)) { - /* - * SRC0 can downsample 4, 6 and 8 channel audio up to 4 times. - * SRC1, SRC3 and SRC4 can downsample 4 channel audio - * up to 4 times. - * SRC1, SRC3 and SRC4 can downsample 6 and 8 channel audio - * no more than twice. - */ - case 1: - case 3: - case 4: - if (channel > 4) { - k_down = 2; - break; - } - fallthrough; - case 0: - if (channel > 2) - k_down = 4; - break; - - /* Other SRC units do not support more than 2 channels */ - default: - if (channel > 2) - return -EINVAL; - } - - if (params_rate(hw_params) > io->converted_rate * k_down) { - hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min = - io->converted_rate * k_down; - hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max = - io->converted_rate * k_down; - hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE; - } else if (params_rate(hw_params) * k_up < io->converted_rate) { - hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min = - DIV_ROUND_UP(io->converted_rate, k_up); - hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max = - DIV_ROUND_UP(io->converted_rate, k_up); - hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE; - } - - /* - * TBD: Max SRC input and output rates also depend on number - * of channels and SRC unit: - * SRC1, SRC3 and SRC4 do not support more than 128kHz - * for 6 channel and 96kHz for 8 channel audio. - * Perhaps this function should return EINVAL if the input or - * the output rate exceeds the limitation. - */ - } - } - - return rsnd_hw_update(substream, hw_params); -} - -static int rsnd_hw_free(struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - return rsnd_hw_update(substream, NULL); -} - -static snd_pcm_uframes_t rsnd_pointer(struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); - snd_pcm_uframes_t pointer = 0; - - rsnd_dai_call(pointer, io, &pointer); - - return pointer; -} - -/* - * snd_kcontrol - */ -static int rsnd_kctrl_info(struct snd_kcontrol *kctrl, - struct snd_ctl_elem_info *uinfo) -{ - struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl); - - if (cfg->texts) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = cfg->size; - uinfo->value.enumerated.items = cfg->max; - if (uinfo->value.enumerated.item >= cfg->max) - uinfo->value.enumerated.item = cfg->max - 1; - strscpy(uinfo->value.enumerated.name, - cfg->texts[uinfo->value.enumerated.item], - sizeof(uinfo->value.enumerated.name)); - } else { - uinfo->count = cfg->size; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = cfg->max; - uinfo->type = (cfg->max == 1) ? - SNDRV_CTL_ELEM_TYPE_BOOLEAN : - SNDRV_CTL_ELEM_TYPE_INTEGER; - } - - return 0; -} - -static int rsnd_kctrl_get(struct snd_kcontrol *kctrl, - struct snd_ctl_elem_value *uc) -{ - struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl); - int i; - - for (i = 0; i < cfg->size; i++) - if (cfg->texts) - uc->value.enumerated.item[i] = cfg->val[i]; - else - uc->value.integer.value[i] = cfg->val[i]; - - return 0; -} - -static int rsnd_kctrl_put(struct snd_kcontrol *kctrl, - struct snd_ctl_elem_value *uc) -{ - struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl); - int i, change = 0; - - if (!cfg->accept(cfg->io)) - return 0; - - for (i = 0; i < cfg->size; i++) { - if (cfg->texts) { - change |= (uc->value.enumerated.item[i] != cfg->val[i]); - cfg->val[i] = uc->value.enumerated.item[i]; - } else { - change |= (uc->value.integer.value[i] != cfg->val[i]); - cfg->val[i] = uc->value.integer.value[i]; - } - } - - if (change && cfg->update) - cfg->update(cfg->io, cfg->mod); - - return change; -} - -int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io) -{ - return 1; -} - -int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct device *dev = rsnd_priv_to_dev(priv); - - if (!runtime) { - dev_warn(dev, "Can't update kctrl when idle\n"); - return 0; - } - - return 1; -} - -struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg) -{ - cfg->cfg.val = cfg->val; - - return &cfg->cfg; -} - -struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg) -{ - cfg->cfg.val = &cfg->val; - - return &cfg->cfg; -} - -const char * const volume_ramp_rate[] = { - "128 dB/1 step", /* 00000 */ - "64 dB/1 step", /* 00001 */ - "32 dB/1 step", /* 00010 */ - "16 dB/1 step", /* 00011 */ - "8 dB/1 step", /* 00100 */ - "4 dB/1 step", /* 00101 */ - "2 dB/1 step", /* 00110 */ - "1 dB/1 step", /* 00111 */ - "0.5 dB/1 step", /* 01000 */ - "0.25 dB/1 step", /* 01001 */ - "0.125 dB/1 step", /* 01010 = VOLUME_RAMP_MAX_MIX */ - "0.125 dB/2 steps", /* 01011 */ - "0.125 dB/4 steps", /* 01100 */ - "0.125 dB/8 steps", /* 01101 */ - "0.125 dB/16 steps", /* 01110 */ - "0.125 dB/32 steps", /* 01111 */ - "0.125 dB/64 steps", /* 10000 */ - "0.125 dB/128 steps", /* 10001 */ - "0.125 dB/256 steps", /* 10010 */ - "0.125 dB/512 steps", /* 10011 */ - "0.125 dB/1024 steps", /* 10100 */ - "0.125 dB/2048 steps", /* 10101 */ - "0.125 dB/4096 steps", /* 10110 */ - "0.125 dB/8192 steps", /* 10111 = VOLUME_RAMP_MAX_DVC */ -}; - -int rsnd_kctrl_new(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd, - const unsigned char *name, - int (*accept)(struct rsnd_dai_stream *io), - void (*update)(struct rsnd_dai_stream *io, - struct rsnd_mod *mod), - struct rsnd_kctrl_cfg *cfg, - const char * const *texts, - int size, - u32 max) -{ - struct snd_card *card = rtd->card->snd_card; - struct snd_kcontrol *kctrl; - struct snd_kcontrol_new knew = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = name, - .info = rsnd_kctrl_info, - .index = rtd->num, - .get = rsnd_kctrl_get, - .put = rsnd_kctrl_put, - }; - int ret; - - /* - * 1) Avoid duplicate register for DVC with MIX case - * 2) Allow duplicate register for MIX - * 3) re-register if card was rebinded - */ - list_for_each_entry(kctrl, &card->controls, list) { - struct rsnd_kctrl_cfg *c = kctrl->private_data; - - if (c == cfg) - return 0; - } - - if (size > RSND_MAX_CHANNELS) - return -EINVAL; - - kctrl = snd_ctl_new1(&knew, cfg); - if (!kctrl) - return -ENOMEM; - - ret = snd_ctl_add(card, kctrl); - if (ret < 0) - return ret; - - cfg->texts = texts; - cfg->max = max; - cfg->size = size; - cfg->accept = accept; - cfg->update = update; - cfg->card = card; - cfg->kctrl = kctrl; - cfg->io = io; - cfg->mod = mod; - - return 0; -} - -/* - * snd_soc_component - */ -static const struct snd_soc_component_driver rsnd_soc_component = { - .name = "rsnd", - .probe = rsnd_debugfs_probe, - .hw_params = rsnd_hw_params, - .hw_free = rsnd_hw_free, - .pointer = rsnd_pointer, - .legacy_dai_naming = 1, -}; - -static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, - struct rsnd_dai_stream *io) -{ - int ret; - - ret = rsnd_dai_call(probe, io, priv); - if (ret == -EAGAIN) { - struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); - struct rsnd_mod *mod; - int i; - - /* - * Fallback to PIO mode - */ - - /* - * call "remove" for SSI/SRC/DVC - * SSI will be switch to PIO mode if it was DMA mode - * see - * rsnd_dma_init() - * rsnd_ssi_fallback() - */ - rsnd_dai_call(remove, io, priv); - - /* - * remove all mod from io - * and, re connect ssi - */ - for_each_rsnd_mod(i, mod, io) - rsnd_dai_disconnect(mod, io, i); - rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI); - - /* - * fallback - */ - rsnd_dai_call(fallback, io, priv); - - /* - * retry to "probe". - * DAI has SSI which is PIO mode only now. - */ - ret = rsnd_dai_call(probe, io, priv); - } - - return ret; -} - -/* - * rsnd probe - */ -static int rsnd_probe(struct platform_device *pdev) -{ - struct rsnd_priv *priv; - struct device *dev = &pdev->dev; - struct rsnd_dai *rdai; - int (*probe_func[])(struct rsnd_priv *priv) = { - rsnd_gen_probe, - rsnd_dma_probe, - rsnd_ssi_probe, - rsnd_ssiu_probe, - rsnd_src_probe, - rsnd_ctu_probe, - rsnd_mix_probe, - rsnd_dvc_probe, - rsnd_cmd_probe, - rsnd_adg_probe, - rsnd_dai_probe, - }; - int ret, i; - int ci; - - /* - * init priv data - */ - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENODEV; - - priv->pdev = pdev; - priv->flags = (unsigned long)of_device_get_match_data(dev); - spin_lock_init(&priv->lock); - - /* - * init each module - */ - for (i = 0; i < ARRAY_SIZE(probe_func); i++) { - ret = probe_func[i](priv); - if (ret) - return ret; - } - - for_each_rsnd_dai(rdai, priv, i) { - ret = rsnd_rdai_continuance_probe(priv, &rdai->playback); - if (ret) - goto exit_snd_probe; - - ret = rsnd_rdai_continuance_probe(priv, &rdai->capture); - if (ret) - goto exit_snd_probe; - } - - dev_set_drvdata(dev, priv); - - /* - * asoc register - */ - ci = 0; - for (i = 0; priv->component_dais[i] > 0; i++) { - int nr = priv->component_dais[i]; - - ret = devm_snd_soc_register_component(dev, &rsnd_soc_component, - priv->daidrv + ci, nr); - if (ret < 0) { - dev_err(dev, "cannot snd component register\n"); - goto exit_snd_probe; - } - - ci += nr; - } - - pm_runtime_enable(dev); - - dev_info(dev, "probed\n"); - return ret; - -exit_snd_probe: - for_each_rsnd_dai(rdai, priv, i) { - rsnd_dai_call(remove, &rdai->playback, priv); - rsnd_dai_call(remove, &rdai->capture, priv); - } - - /* - * adg is very special mod which can't use rsnd_dai_call(remove), - * and it registers ADG clock on probe. - * It should be unregister if probe failed. - * Mainly it is assuming -EPROBE_DEFER case - */ - rsnd_adg_remove(priv); - - return ret; -} - -static void rsnd_remove(struct platform_device *pdev) -{ - struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); - struct rsnd_dai *rdai; - void (*remove_func[])(struct rsnd_priv *priv) = { - rsnd_ssi_remove, - rsnd_ssiu_remove, - rsnd_src_remove, - rsnd_ctu_remove, - rsnd_mix_remove, - rsnd_dvc_remove, - rsnd_cmd_remove, - rsnd_adg_remove, - }; - int i; - - pm_runtime_disable(&pdev->dev); - - for_each_rsnd_dai(rdai, priv, i) { - int ret; - - ret = rsnd_dai_call(remove, &rdai->playback, priv); - if (ret) - dev_warn(&pdev->dev, "Failed to remove playback dai #%d\n", i); - - ret = rsnd_dai_call(remove, &rdai->capture, priv); - if (ret) - dev_warn(&pdev->dev, "Failed to remove capture dai #%d\n", i); - } - - for (i = 0; i < ARRAY_SIZE(remove_func); i++) - remove_func[i](priv); -} - -static int __maybe_unused rsnd_suspend(struct device *dev) -{ - struct rsnd_priv *priv = dev_get_drvdata(dev); - - rsnd_adg_clk_disable(priv); - - return 0; -} - -static int __maybe_unused rsnd_resume(struct device *dev) -{ - struct rsnd_priv *priv = dev_get_drvdata(dev); - - rsnd_adg_clk_enable(priv); - - return 0; -} - -static const struct dev_pm_ops rsnd_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(rsnd_suspend, rsnd_resume) -}; - -static struct platform_driver rsnd_driver = { - .driver = { - .name = "rcar_sound", - .pm = &rsnd_pm_ops, - .of_match_table = rsnd_of_match, - }, - .probe = rsnd_probe, - .remove_new = rsnd_remove, -}; -module_platform_driver(rsnd_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Renesas R-Car audio driver"); -MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); -MODULE_ALIAS("platform:rcar-pcm-audio"); diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c deleted file mode 100644 index e39eb2ac7e95..000000000000 --- a/sound/soc/sh/rcar/ctu.c +++ /dev/null @@ -1,393 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// ctu.c -// -// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> - -#include "rsnd.h" - -#define CTU_NAME_SIZE 16 -#define CTU_NAME "ctu" - -/* - * User needs to setup CTU by amixer, and its settings are - * based on below registers - * - * CTUn_CPMDR : amixser set "CTU Pass" - * CTUn_SV0xR : amixser set "CTU SV0" - * CTUn_SV1xR : amixser set "CTU SV1" - * CTUn_SV2xR : amixser set "CTU SV2" - * CTUn_SV3xR : amixser set "CTU SV3" - * - * [CTU Pass] - * 0000: default - * 0001: Connect input data of channel 0 - * 0010: Connect input data of channel 1 - * 0011: Connect input data of channel 2 - * 0100: Connect input data of channel 3 - * 0101: Connect input data of channel 4 - * 0110: Connect input data of channel 5 - * 0111: Connect input data of channel 6 - * 1000: Connect input data of channel 7 - * 1001: Connect calculated data by scale values of matrix row 0 - * 1010: Connect calculated data by scale values of matrix row 1 - * 1011: Connect calculated data by scale values of matrix row 2 - * 1100: Connect calculated data by scale values of matrix row 3 - * - * [CTU SVx] - * [Output0] = [SV00, SV01, SV02, SV03, SV04, SV05, SV06, SV07] - * [Output1] = [SV10, SV11, SV12, SV13, SV14, SV15, SV16, SV17] - * [Output2] = [SV20, SV21, SV22, SV23, SV24, SV25, SV26, SV27] - * [Output3] = [SV30, SV31, SV32, SV33, SV34, SV35, SV36, SV37] - * [Output4] = [ 0, 0, 0, 0, 0, 0, 0, 0 ] - * [Output5] = [ 0, 0, 0, 0, 0, 0, 0, 0 ] - * [Output6] = [ 0, 0, 0, 0, 0, 0, 0, 0 ] - * [Output7] = [ 0, 0, 0, 0, 0, 0, 0, 0 ] - * - * [SVxx] - * Plus Minus - * value time dB value time dB - * ----------------------------------------------------------------------- - * H'7F_FFFF 2 6 H'80_0000 2 6 - * ... - * H'40_0000 1 0 H'C0_0000 1 0 - * ... - * H'00_0001 2.38 x 10^-7 -132 - * H'00_0000 0 Mute H'FF_FFFF 2.38 x 10^-7 -132 - * - * - * Ex) Input ch -> Output ch - * 1ch -> 0ch - * 0ch -> 1ch - * - * amixer set "CTU Reset" on - * amixer set "CTU Pass" 9,10 - * amixer set "CTU SV0" 0,4194304 - * amixer set "CTU SV1" 4194304,0 - * or - * amixer set "CTU Reset" on - * amixer set "CTU Pass" 2,1 - */ - -struct rsnd_ctu { - struct rsnd_mod mod; - struct rsnd_kctrl_cfg_m pass; - struct rsnd_kctrl_cfg_m sv[4]; - struct rsnd_kctrl_cfg_s reset; - int channels; - u32 flags; -}; - -#define KCTRL_INITIALIZED (1 << 0) - -#define rsnd_ctu_nr(priv) ((priv)->ctu_nr) -#define for_each_rsnd_ctu(pos, priv, i) \ - for ((i) = 0; \ - ((i) < rsnd_ctu_nr(priv)) && \ - ((pos) = (struct rsnd_ctu *)(priv)->ctu + i); \ - i++) - -#define rsnd_mod_to_ctu(_mod) \ - container_of((_mod), struct rsnd_ctu, mod) - -#define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id) - -static void rsnd_ctu_activation(struct rsnd_mod *mod) -{ - rsnd_mod_write(mod, CTU_SWRSR, 0); - rsnd_mod_write(mod, CTU_SWRSR, 1); -} - -static void rsnd_ctu_halt(struct rsnd_mod *mod) -{ - rsnd_mod_write(mod, CTU_CTUIR, 1); - rsnd_mod_write(mod, CTU_SWRSR, 0); -} - -static int rsnd_ctu_probe_(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - return rsnd_cmd_attach(io, rsnd_mod_id(mod)); -} - -static void rsnd_ctu_value_init(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); - u32 cpmdr = 0; - u32 scmdr = 0; - int i, j; - - for (i = 0; i < RSND_MAX_CHANNELS; i++) { - u32 val = rsnd_kctrl_valm(ctu->pass, i); - - cpmdr |= val << (28 - (i * 4)); - - if ((val > 0x8) && (scmdr < (val - 0x8))) - scmdr = val - 0x8; - } - - rsnd_mod_write(mod, CTU_CTUIR, 1); - - rsnd_mod_write(mod, CTU_ADINR, rsnd_runtime_channel_original(io)); - - rsnd_mod_write(mod, CTU_CPMDR, cpmdr); - - rsnd_mod_write(mod, CTU_SCMDR, scmdr); - - for (i = 0; i < 4; i++) { - - if (i >= scmdr) - break; - - for (j = 0; j < RSND_MAX_CHANNELS; j++) - rsnd_mod_write(mod, CTU_SVxxR(i, j), rsnd_kctrl_valm(ctu->sv[i], j)); - } - - rsnd_mod_write(mod, CTU_CTUIR, 0); -} - -static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); - int i; - - if (!rsnd_kctrl_vals(ctu->reset)) - return; - - for (i = 0; i < RSND_MAX_CHANNELS; i++) { - rsnd_kctrl_valm(ctu->pass, i) = 0; - rsnd_kctrl_valm(ctu->sv[0], i) = 0; - rsnd_kctrl_valm(ctu->sv[1], i) = 0; - rsnd_kctrl_valm(ctu->sv[2], i) = 0; - rsnd_kctrl_valm(ctu->sv[3], i) = 0; - } - rsnd_kctrl_vals(ctu->reset) = 0; -} - -static int rsnd_ctu_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int ret; - - ret = rsnd_mod_power_on(mod); - if (ret < 0) - return ret; - - rsnd_ctu_activation(mod); - - rsnd_ctu_value_init(io, mod); - - return 0; -} - -static int rsnd_ctu_quit(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - rsnd_ctu_halt(mod); - - rsnd_mod_power_off(mod); - - return 0; -} - -static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd) -{ - struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); - int ret; - - if (rsnd_flags_has(ctu, KCTRL_INITIALIZED)) - return 0; - - /* CTU Pass */ - ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass", - rsnd_kctrl_accept_anytime, - NULL, - &ctu->pass, RSND_MAX_CHANNELS, - 0xC); - if (ret < 0) - return ret; - - /* ROW0 */ - ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0", - rsnd_kctrl_accept_anytime, - NULL, - &ctu->sv[0], RSND_MAX_CHANNELS, - 0x00FFFFFF); - if (ret < 0) - return ret; - - /* ROW1 */ - ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1", - rsnd_kctrl_accept_anytime, - NULL, - &ctu->sv[1], RSND_MAX_CHANNELS, - 0x00FFFFFF); - if (ret < 0) - return ret; - - /* ROW2 */ - ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2", - rsnd_kctrl_accept_anytime, - NULL, - &ctu->sv[2], RSND_MAX_CHANNELS, - 0x00FFFFFF); - if (ret < 0) - return ret; - - /* ROW3 */ - ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3", - rsnd_kctrl_accept_anytime, - NULL, - &ctu->sv[3], RSND_MAX_CHANNELS, - 0x00FFFFFF); - if (ret < 0) - return ret; - - /* Reset */ - ret = rsnd_kctrl_new_s(mod, io, rtd, "CTU Reset", - rsnd_kctrl_accept_anytime, - rsnd_ctu_value_reset, - &ctu->reset, 1); - - rsnd_flags_set(ctu, KCTRL_INITIALIZED); - - return ret; -} - -static int rsnd_ctu_id(struct rsnd_mod *mod) -{ - /* - * ctu00: -> 0, ctu01: -> 0, ctu02: -> 0, ctu03: -> 0 - * ctu10: -> 1, ctu11: -> 1, ctu12: -> 1, ctu13: -> 1 - */ - return mod->id / 4; -} - -static int rsnd_ctu_id_sub(struct rsnd_mod *mod) -{ - /* - * ctu00: -> 0, ctu01: -> 1, ctu02: -> 2, ctu03: -> 3 - * ctu10: -> 0, ctu11: -> 1, ctu12: -> 2, ctu13: -> 3 - */ - return mod->id % 4; -} - -#ifdef CONFIG_DEBUG_FS -static void rsnd_ctu_debug_info(struct seq_file *m, - struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, - 0x500 + rsnd_mod_id_raw(mod) * 0x100, 0x100); -} -#define DEBUG_INFO .debug_info = rsnd_ctu_debug_info -#else -#define DEBUG_INFO -#endif - -static struct rsnd_mod_ops rsnd_ctu_ops = { - .name = CTU_NAME, - .probe = rsnd_ctu_probe_, - .init = rsnd_ctu_init, - .quit = rsnd_ctu_quit, - .pcm_new = rsnd_ctu_pcm_new, - .get_status = rsnd_mod_get_status, - .id = rsnd_ctu_id, - .id_sub = rsnd_ctu_id_sub, - .id_cmd = rsnd_mod_id_raw, - DEBUG_INFO -}; - -struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) -{ - if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv))) - id = 0; - - return rsnd_mod_get(rsnd_ctu_get(priv, id)); -} - -int rsnd_ctu_probe(struct rsnd_priv *priv) -{ - struct device_node *node; - struct device_node *np; - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_ctu *ctu; - struct clk *clk; - char name[CTU_NAME_SIZE]; - int i, nr, ret; - - /* This driver doesn't support Gen1 at this point */ - if (rsnd_is_gen1(priv)) - return 0; - - node = rsnd_ctu_of_node(priv); - if (!node) - return 0; /* not used is not error */ - - nr = of_get_child_count(node); - if (!nr) { - ret = -EINVAL; - goto rsnd_ctu_probe_done; - } - - ctu = devm_kcalloc(dev, nr, sizeof(*ctu), GFP_KERNEL); - if (!ctu) { - ret = -ENOMEM; - goto rsnd_ctu_probe_done; - } - - priv->ctu_nr = nr; - priv->ctu = ctu; - - i = 0; - ret = 0; - for_each_child_of_node(node, np) { - ctu = rsnd_ctu_get(priv, i); - - /* - * CTU00, CTU01, CTU02, CTU03 => CTU0 - * CTU10, CTU11, CTU12, CTU13 => CTU1 - */ - snprintf(name, CTU_NAME_SIZE, "%s.%d", - CTU_NAME, i / 4); - - clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - of_node_put(np); - goto rsnd_ctu_probe_done; - } - - ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops, - clk, RSND_MOD_CTU, i); - if (ret) { - of_node_put(np); - goto rsnd_ctu_probe_done; - } - - i++; - } - - -rsnd_ctu_probe_done: - of_node_put(node); - - return ret; -} - -void rsnd_ctu_remove(struct rsnd_priv *priv) -{ - struct rsnd_ctu *ctu; - int i; - - for_each_rsnd_ctu(ctu, priv, i) { - rsnd_mod_quit(rsnd_mod_get(ctu)); - } -} diff --git a/sound/soc/sh/rcar/debugfs.c b/sound/soc/sh/rcar/debugfs.c deleted file mode 100644 index 26d3b310b9db..000000000000 --- a/sound/soc/sh/rcar/debugfs.c +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// // Renesas R-Car debugfs support -// -// Copyright (c) 2021 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> -// -// > mount -t debugfs none /sys/kernel/debug -// > cd /sys/kernel/debug/asoc/rcar-sound/ec500000.sound/rdai{N}/ -// > cat playback/xxx -// > cat capture/xxx -// -#ifdef CONFIG_DEBUG_FS - -#include <linux/debugfs.h> -#include "rsnd.h" - -static int rsnd_debugfs_show(struct seq_file *m, void *v) -{ - struct rsnd_dai_stream *io = m->private; - struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - int i; - - /* adg is out of mods */ - rsnd_adg_clk_dbg_info(priv, m); - - for_each_rsnd_mod(i, mod, io) { - u32 *status = mod->ops->get_status(mod, io, mod->type); - - seq_printf(m, "name: %s\n", rsnd_mod_name(mod)); - seq_printf(m, "status: %08x\n", *status); - - if (mod->ops->debug_info) - mod->ops->debug_info(m, io, mod); - } - - return 0; -} -DEFINE_SHOW_ATTRIBUTE(rsnd_debugfs); - -void rsnd_debugfs_reg_show(struct seq_file *m, phys_addr_t _addr, - void __iomem *base, int offset, int size) -{ - int i, j; - - for (i = 0; i < size; i += 0x10) { - phys_addr_t addr = _addr + offset + i; - - seq_printf(m, "%pa:", &addr); - for (j = 0; j < 0x10; j += 0x4) - seq_printf(m, " %08x", __raw_readl(base + offset + i + j)); - seq_puts(m, "\n"); - } -} - -void rsnd_debugfs_mod_reg_show(struct seq_file *m, struct rsnd_mod *mod, - int reg_id, int offset, int size) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - - rsnd_debugfs_reg_show(m, - rsnd_gen_get_phy_addr(priv, reg_id), - rsnd_gen_get_base_addr(priv, reg_id), - offset, size); -} - -int rsnd_debugfs_probe(struct snd_soc_component *component) -{ - struct rsnd_priv *priv = dev_get_drvdata(component->dev); - struct rsnd_dai *rdai; - struct dentry *dir; - char name[64]; - int i; - - /* Gen1 is not supported */ - if (rsnd_is_gen1(priv)) - return 0; - - for_each_rsnd_dai(rdai, priv, i) { - /* - * created debugfs will be automatically - * removed, nothing to do for _remove. - * see - * soc_cleanup_component_debugfs() - */ - snprintf(name, sizeof(name), "rdai%d", i); - dir = debugfs_create_dir(name, component->debugfs_root); - - debugfs_create_file("playback", 0444, dir, &rdai->playback, &rsnd_debugfs_fops); - debugfs_create_file("capture", 0444, dir, &rdai->capture, &rsnd_debugfs_fops); - } - - return 0; -} - -#endif /* CONFIG_DEBUG_FS */ diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c deleted file mode 100644 index 1c494e521463..000000000000 --- a/sound/soc/sh/rcar/dma.c +++ /dev/null @@ -1,946 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas R-Car Audio DMAC support -// -// Copyright (C) 2015 Renesas Electronics Corp. -// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> - -#include <linux/delay.h> -#include <linux/of_dma.h> -#include "rsnd.h" - -/* - * Audio DMAC peri peri register - */ -#define PDMASAR 0x00 -#define PDMADAR 0x04 -#define PDMACHCR 0x0c - -/* PDMACHCR */ -#define PDMACHCR_DE (1 << 0) - - -struct rsnd_dmaen { - struct dma_chan *chan; - dma_cookie_t cookie; - unsigned int dma_len; -}; - -struct rsnd_dmapp { - int dmapp_id; - u32 chcr; -}; - -struct rsnd_dma { - struct rsnd_mod mod; - struct rsnd_mod *mod_from; - struct rsnd_mod *mod_to; - dma_addr_t src_addr; - dma_addr_t dst_addr; - union { - struct rsnd_dmaen en; - struct rsnd_dmapp pp; - } dma; -}; - -struct rsnd_dma_ctrl { - void __iomem *ppbase; - phys_addr_t ppres; - int dmaen_num; - int dmapp_num; -}; - -#define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma) -#define rsnd_mod_to_dma(_mod) container_of((_mod), struct rsnd_dma, mod) -#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en) -#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp) - -/* for DEBUG */ -static struct rsnd_mod_ops mem_ops = { - .name = "mem", -}; - -static struct rsnd_mod mem = { -}; - -/* - * Audio DMAC - */ -static void __rsnd_dmaen_complete(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - if (rsnd_io_is_working(io)) - rsnd_dai_period_elapsed(io); -} - -static void rsnd_dmaen_complete(void *data) -{ - struct rsnd_mod *mod = data; - - rsnd_mod_interrupt(mod, __rsnd_dmaen_complete); -} - -static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, - struct rsnd_mod *mod_from, - struct rsnd_mod *mod_to) -{ - if ((!mod_from && !mod_to) || - (mod_from && mod_to)) - return NULL; - - if (mod_from) - return rsnd_mod_dma_req(io, mod_from); - else - return rsnd_mod_dma_req(io, mod_to); -} - -static int rsnd_dmaen_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - - if (dmaen->chan) - dmaengine_terminate_async(dmaen->chan); - - return 0; -} - -static int rsnd_dmaen_cleanup(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - - /* - * DMAEngine release uses mutex lock. - * Thus, it shouldn't be called under spinlock. - * Let's call it under prepare - */ - if (dmaen->chan) - dma_release_channel(dmaen->chan); - - dmaen->chan = NULL; - - return 0; -} - -static int rsnd_dmaen_prepare(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - struct device *dev = rsnd_priv_to_dev(priv); - - /* maybe suspended */ - if (dmaen->chan) - return 0; - - /* - * DMAEngine request uses mutex lock. - * Thus, it shouldn't be called under spinlock. - * Let's call it under prepare - */ - dmaen->chan = rsnd_dmaen_request_channel(io, - dma->mod_from, - dma->mod_to); - if (IS_ERR_OR_NULL(dmaen->chan)) { - dmaen->chan = NULL; - dev_err(dev, "can't get dma channel\n"); - return -EIO; - } - - return 0; -} - -static int rsnd_dmaen_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - struct snd_pcm_substream *substream = io->substream; - struct device *dev = rsnd_priv_to_dev(priv); - struct dma_async_tx_descriptor *desc; - struct dma_slave_config cfg = {}; - enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; - int is_play = rsnd_io_is_play(io); - int ret; - - /* - * in case of monaural data writing or reading through Audio-DMAC - * data is always in Left Justified format, so both src and dst - * DMA Bus width need to be set equal to physical data width. - */ - if (rsnd_runtime_channel_original(io) == 1) { - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - int bits = snd_pcm_format_physical_width(runtime->format); - - switch (bits) { - case 8: - buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; - break; - case 16: - buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; - break; - case 32: - buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; - break; - default: - dev_err(dev, "invalid format width %d\n", bits); - return -EINVAL; - } - } - - cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; - cfg.src_addr = dma->src_addr; - cfg.dst_addr = dma->dst_addr; - cfg.src_addr_width = buswidth; - cfg.dst_addr_width = buswidth; - - dev_dbg(dev, "%s %pad -> %pad\n", - rsnd_mod_name(mod), - &cfg.src_addr, &cfg.dst_addr); - - ret = dmaengine_slave_config(dmaen->chan, &cfg); - if (ret < 0) - return ret; - - desc = dmaengine_prep_dma_cyclic(dmaen->chan, - substream->runtime->dma_addr, - snd_pcm_lib_buffer_bytes(substream), - snd_pcm_lib_period_bytes(substream), - is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - - if (!desc) { - dev_err(dev, "dmaengine_prep_slave_sg() fail\n"); - return -EIO; - } - - desc->callback = rsnd_dmaen_complete; - desc->callback_param = rsnd_mod_get(dma); - - dmaen->dma_len = snd_pcm_lib_buffer_bytes(substream); - - dmaen->cookie = dmaengine_submit(desc); - if (dmaen->cookie < 0) { - dev_err(dev, "dmaengine_submit() fail\n"); - return -EIO; - } - - dma_async_issue_pending(dmaen->chan); - - return 0; -} - -struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name, - struct rsnd_mod *mod, char *x) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - struct dma_chan *chan = NULL; - struct device_node *np; - int i = 0; - - for_each_child_of_node(of_node, np) { - i = rsnd_node_fixed_index(dev, np, name, i); - if (i < 0) { - chan = NULL; - of_node_put(np); - break; - } - - if (i == rsnd_mod_id_raw(mod) && (!chan)) - chan = of_dma_request_slave_channel(np, x); - i++; - } - - /* It should call of_node_put(), since, it is rsnd_xxx_of_node() */ - of_node_put(of_node); - - return chan; -} - -static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, - struct rsnd_dma *dma, - struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) -{ - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - struct dma_chan *chan; - - /* try to get DMAEngine channel */ - chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); - if (IS_ERR_OR_NULL(chan)) { - /* Let's follow when -EPROBE_DEFER case */ - if (PTR_ERR(chan) == -EPROBE_DEFER) - return PTR_ERR(chan); - - /* - * DMA failed. try to PIO mode - * see - * rsnd_ssi_fallback() - * rsnd_rdai_continuance_probe() - */ - return -EAGAIN; - } - - /* - * use it for IPMMU if needed - * see - * rsnd_preallocate_pages() - */ - io->dmac_dev = chan->device->dev; - - dma_release_channel(chan); - - dmac->dmaen_num++; - - return 0; -} - -static int rsnd_dmaen_pointer(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - snd_pcm_uframes_t *pointer) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - struct dma_tx_state state; - enum dma_status status; - unsigned int pos = 0; - - status = dmaengine_tx_status(dmaen->chan, dmaen->cookie, &state); - if (status == DMA_IN_PROGRESS || status == DMA_PAUSED) { - if (state.residue > 0 && state.residue <= dmaen->dma_len) - pos = dmaen->dma_len - state.residue; - } - *pointer = bytes_to_frames(runtime, pos); - - return 0; -} - -static struct rsnd_mod_ops rsnd_dmaen_ops = { - .name = "audmac", - .prepare = rsnd_dmaen_prepare, - .cleanup = rsnd_dmaen_cleanup, - .start = rsnd_dmaen_start, - .stop = rsnd_dmaen_stop, - .pointer = rsnd_dmaen_pointer, - .get_status = rsnd_mod_get_status, -}; - -/* - * Audio DMAC peri peri - */ -static const u8 gen2_id_table_ssiu[] = { - /* SSI00 ~ SSI07 */ - 0x00, 0x01, 0x02, 0x03, 0x39, 0x3a, 0x3b, 0x3c, - /* SSI10 ~ SSI17 */ - 0x04, 0x05, 0x06, 0x07, 0x3d, 0x3e, 0x3f, 0x40, - /* SSI20 ~ SSI27 */ - 0x08, 0x09, 0x0a, 0x0b, 0x41, 0x42, 0x43, 0x44, - /* SSI30 ~ SSI37 */ - 0x0c, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, - /* SSI40 ~ SSI47 */ - 0x0d, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, - /* SSI5 */ - 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* SSI6 */ - 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* SSI7 */ - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* SSI8 */ - 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* SSI90 ~ SSI97 */ - 0x12, 0x13, 0x14, 0x15, 0x53, 0x54, 0x55, 0x56, -}; -static const u8 gen2_id_table_scu[] = { - 0x2d, /* SCU_SRCI0 */ - 0x2e, /* SCU_SRCI1 */ - 0x2f, /* SCU_SRCI2 */ - 0x30, /* SCU_SRCI3 */ - 0x31, /* SCU_SRCI4 */ - 0x32, /* SCU_SRCI5 */ - 0x33, /* SCU_SRCI6 */ - 0x34, /* SCU_SRCI7 */ - 0x35, /* SCU_SRCI8 */ - 0x36, /* SCU_SRCI9 */ -}; -static const u8 gen2_id_table_cmd[] = { - 0x37, /* SCU_CMD0 */ - 0x38, /* SCU_CMD1 */ -}; - -static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); - struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); - struct rsnd_mod *src = rsnd_io_to_mod_src(io); - struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); - const u8 *entry = NULL; - int id = 255; - int size = 0; - - if ((mod == ssi) || - (mod == ssiu)) { - int busif = rsnd_mod_id_sub(ssiu); - - entry = gen2_id_table_ssiu; - size = ARRAY_SIZE(gen2_id_table_ssiu); - id = (rsnd_mod_id(mod) * 8) + busif; - } else if (mod == src) { - entry = gen2_id_table_scu; - size = ARRAY_SIZE(gen2_id_table_scu); - id = rsnd_mod_id(mod); - } else if (mod == dvc) { - entry = gen2_id_table_cmd; - size = ARRAY_SIZE(gen2_id_table_cmd); - id = rsnd_mod_id(mod); - } - - if ((!entry) || (size <= id)) { - struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); - - dev_err(dev, "unknown connection (%s)\n", rsnd_mod_name(mod)); - - /* use non-prohibited SRS number as error */ - return 0x00; /* SSI00 */ - } - - return entry[id]; -} - -static u32 rsnd_dmapp_get_chcr(struct rsnd_dai_stream *io, - struct rsnd_mod *mod_from, - struct rsnd_mod *mod_to) -{ - return (rsnd_dmapp_get_id(io, mod_from) << 24) + - (rsnd_dmapp_get_id(io, mod_to) << 16); -} - -#define rsnd_dmapp_addr(dmac, dma, reg) \ - (dmac->ppbase + 0x20 + reg + \ - (0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id)) -static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg) -{ - struct rsnd_mod *mod = rsnd_mod_get(dma); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - struct device *dev = rsnd_priv_to_dev(priv); - - dev_dbg(dev, "w 0x%px : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data); - - iowrite32(data, rsnd_dmapp_addr(dmac, dma, reg)); -} - -static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg) -{ - struct rsnd_mod *mod = rsnd_mod_get(dma); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - - return ioread32(rsnd_dmapp_addr(dmac, dma, reg)); -} - -static void rsnd_dmapp_bset(struct rsnd_dma *dma, u32 data, u32 mask, u32 reg) -{ - struct rsnd_mod *mod = rsnd_mod_get(dma); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - void __iomem *addr = rsnd_dmapp_addr(dmac, dma, reg); - u32 val = ioread32(addr); - - val &= ~mask; - val |= (data & mask); - - iowrite32(val, addr); -} - -static int rsnd_dmapp_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - int i; - - rsnd_dmapp_bset(dma, 0, PDMACHCR_DE, PDMACHCR); - - for (i = 0; i < 1024; i++) { - if (0 == (rsnd_dmapp_read(dma, PDMACHCR) & PDMACHCR_DE)) - return 0; - udelay(1); - } - - return -EIO; -} - -static int rsnd_dmapp_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); - - rsnd_dmapp_write(dma, dma->src_addr, PDMASAR); - rsnd_dmapp_write(dma, dma->dst_addr, PDMADAR); - rsnd_dmapp_write(dma, dmapp->chcr, PDMACHCR); - - return 0; -} - -static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, - struct rsnd_dma *dma, - struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) -{ - struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - struct device *dev = rsnd_priv_to_dev(priv); - - dmapp->dmapp_id = dmac->dmapp_num; - dmapp->chcr = rsnd_dmapp_get_chcr(io, mod_from, mod_to) | PDMACHCR_DE; - - dmac->dmapp_num++; - - dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n", - dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr); - - return 0; -} - -#ifdef CONFIG_DEBUG_FS -static void rsnd_dmapp_debug_info(struct seq_file *m, - struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); - - rsnd_debugfs_reg_show(m, dmac->ppres, dmac->ppbase, - 0x20 + 0x10 * dmapp->dmapp_id, 0x10); -} -#define DEBUG_INFO .debug_info = rsnd_dmapp_debug_info -#else -#define DEBUG_INFO -#endif - -static struct rsnd_mod_ops rsnd_dmapp_ops = { - .name = "audmac-pp", - .start = rsnd_dmapp_start, - .stop = rsnd_dmapp_stop, - .quit = rsnd_dmapp_stop, - .get_status = rsnd_mod_get_status, - DEBUG_INFO -}; - -/* - * Common DMAC Interface - */ - -/* - * DMA read/write register offset - * - * RSND_xxx_I_N for Audio DMAC input - * RSND_xxx_O_N for Audio DMAC output - * RSND_xxx_I_P for Audio DMAC peri peri input - * RSND_xxx_O_P for Audio DMAC peri peri output - * - * ex) R-Car H2 case - * mod / DMAC in / DMAC out / DMAC PP in / DMAC pp out - * SSI : 0xec541000 / 0xec241008 / 0xec24100c - * SSIU: 0xec541000 / 0xec100000 / 0xec100000 / 0xec400000 / 0xec400000 - * SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000 - * CMD : 0xec500000 / / 0xec008000 0xec308000 - */ -#define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8) -#define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc) - -#define RDMA_SSIU_I_N(addr, i, j) (addr ##_reg - 0x00441000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400) - (0x4000 * ((i) / 9) * ((j) / 4))) -#define RDMA_SSIU_O_N(addr, i, j) RDMA_SSIU_I_N(addr, i, j) - -#define RDMA_SSIU_I_P(addr, i, j) (addr ##_reg - 0x00141000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400) - (0x4000 * ((i) / 9) * ((j) / 4))) -#define RDMA_SSIU_O_P(addr, i, j) RDMA_SSIU_I_P(addr, i, j) - -#define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i)) -#define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i)) - -#define RDMA_SRC_I_P(addr, i) (addr ##_reg - 0x00200000 + (0x400 * i)) -#define RDMA_SRC_O_P(addr, i) (addr ##_reg - 0x001fc000 + (0x400 * i)) - -#define RDMA_CMD_O_N(addr, i) (addr ##_reg - 0x004f8000 + (0x400 * i)) -#define RDMA_CMD_O_P(addr, i) (addr ##_reg - 0x001f8000 + (0x400 * i)) - -static dma_addr_t -rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, - int is_play, int is_from) -{ - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct device *dev = rsnd_priv_to_dev(priv); - phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SSI); - phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU); - int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod) || - !!(rsnd_io_to_mod_ssiu(io) == mod); - int use_src = !!rsnd_io_to_mod_src(io); - int use_cmd = !!rsnd_io_to_mod_dvc(io) || - !!rsnd_io_to_mod_mix(io) || - !!rsnd_io_to_mod_ctu(io); - int id = rsnd_mod_id(mod); - int busif = rsnd_mod_id_sub(rsnd_io_to_mod_ssiu(io)); - struct dma_addr { - dma_addr_t out_addr; - dma_addr_t in_addr; - } dma_addrs[3][2][3] = { - /* SRC */ - /* Capture */ - {{{ 0, 0 }, - { RDMA_SRC_O_N(src, id), RDMA_SRC_I_P(src, id) }, - { RDMA_CMD_O_N(src, id), RDMA_SRC_I_P(src, id) } }, - /* Playback */ - {{ 0, 0, }, - { RDMA_SRC_O_P(src, id), RDMA_SRC_I_N(src, id) }, - { RDMA_CMD_O_P(src, id), RDMA_SRC_I_N(src, id) } } - }, - /* SSI */ - /* Capture */ - {{{ RDMA_SSI_O_N(ssi, id), 0 }, - { RDMA_SSIU_O_P(ssi, id, busif), 0 }, - { RDMA_SSIU_O_P(ssi, id, busif), 0 } }, - /* Playback */ - {{ 0, RDMA_SSI_I_N(ssi, id) }, - { 0, RDMA_SSIU_I_P(ssi, id, busif) }, - { 0, RDMA_SSIU_I_P(ssi, id, busif) } } - }, - /* SSIU */ - /* Capture */ - {{{ RDMA_SSIU_O_N(ssi, id, busif), 0 }, - { RDMA_SSIU_O_P(ssi, id, busif), 0 }, - { RDMA_SSIU_O_P(ssi, id, busif), 0 } }, - /* Playback */ - {{ 0, RDMA_SSIU_I_N(ssi, id, busif) }, - { 0, RDMA_SSIU_I_P(ssi, id, busif) }, - { 0, RDMA_SSIU_I_P(ssi, id, busif) } } }, - }; - - /* - * FIXME - * - * We can't support SSI9-4/5/6/7, because its address is - * out of calculation rule - */ - if ((id == 9) && (busif >= 4)) - dev_err(dev, "This driver doesn't support SSI%d-%d, so far", - id, busif); - - /* it shouldn't happen */ - if (use_cmd && !use_src) - dev_err(dev, "DVC is selected without SRC\n"); - - /* use SSIU or SSI ? */ - if (is_ssi && rsnd_ssi_use_busif(io)) - is_ssi++; - - return (is_from) ? - dma_addrs[is_ssi][is_play][use_src + use_cmd].out_addr : - dma_addrs[is_ssi][is_play][use_src + use_cmd].in_addr; -} - -/* - * Gen4 DMA read/write register offset - * - * ex) R-Car V4H case - * mod / SYS-DMAC in / SYS-DMAC out - * SSI_SDMC: 0xec400000 / 0xec400000 / 0xec400000 - */ -#define RDMA_SSI_SDMC(addr, i) (addr + (0x8000 * i)) -static dma_addr_t -rsnd_gen4_dma_addr(struct rsnd_dai_stream *io, struct rsnd_mod *mod, - int is_play, int is_from) -{ - struct rsnd_priv *priv = rsnd_io_to_priv(io); - phys_addr_t addr = rsnd_gen_get_phy_addr(priv, RSND_GEN4_SDMC); - int id = rsnd_mod_id(mod); - int busif = rsnd_mod_id_sub(mod); - - /* - * SSI0 only is supported - */ - if (id != 0) { - struct device *dev = rsnd_priv_to_dev(priv); - - dev_err(dev, "This driver doesn't support non SSI0"); - return -EINVAL; - } - - return RDMA_SSI_SDMC(addr, busif); -} - -static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, - int is_play, int is_from) -{ - struct rsnd_priv *priv = rsnd_io_to_priv(io); - - if (!mod) - return 0; - - /* - * gen1 uses default DMA addr - */ - if (rsnd_is_gen1(priv)) - return 0; - else if (rsnd_is_gen4(priv)) - return rsnd_gen4_dma_addr(io, mod, is_play, is_from); - else - return rsnd_gen2_dma_addr(io, mod, is_play, is_from); -} - -#define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */ -static void rsnd_dma_of_path(struct rsnd_mod *this, - struct rsnd_dai_stream *io, - int is_play, - struct rsnd_mod **mod_from, - struct rsnd_mod **mod_to) -{ - struct rsnd_mod *ssi; - struct rsnd_mod *src = rsnd_io_to_mod_src(io); - struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io); - struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); - struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); - struct rsnd_mod *mod[MOD_MAX]; - struct rsnd_mod *mod_start, *mod_end; - struct rsnd_priv *priv = rsnd_mod_to_priv(this); - struct device *dev = rsnd_priv_to_dev(priv); - int nr, i, idx; - - /* - * It should use "rcar_sound,ssiu" on DT. - * But, we need to keep compatibility for old version. - * - * If it has "rcar_sound.ssiu", it will be used. - * If not, "rcar_sound.ssi" will be used. - * see - * rsnd_ssiu_dma_req() - * rsnd_ssi_dma_req() - */ - if (rsnd_ssiu_of_node(priv)) { - struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); - - /* use SSIU */ - ssi = ssiu; - if (this == rsnd_io_to_mod_ssi(io)) - this = ssiu; - } else { - /* keep compatible, use SSI */ - ssi = rsnd_io_to_mod_ssi(io); - } - - if (!ssi) - return; - - nr = 0; - for (i = 0; i < MOD_MAX; i++) { - mod[i] = NULL; - nr += !!rsnd_io_to_mod(io, i); - } - - /* - * [S] -*-> [E] - * [S] -*-> SRC -o-> [E] - * [S] -*-> SRC -> DVC -o-> [E] - * [S] -*-> SRC -> CTU -> MIX -> DVC -o-> [E] - * - * playback [S] = mem - * [E] = SSI - * - * capture [S] = SSI - * [E] = mem - * - * -*-> Audio DMAC - * -o-> Audio DMAC peri peri - */ - mod_start = (is_play) ? NULL : ssi; - mod_end = (is_play) ? ssi : NULL; - - idx = 0; - mod[idx++] = mod_start; - for (i = 1; i < nr; i++) { - if (src) { - mod[idx++] = src; - src = NULL; - } else if (ctu) { - mod[idx++] = ctu; - ctu = NULL; - } else if (mix) { - mod[idx++] = mix; - mix = NULL; - } else if (dvc) { - mod[idx++] = dvc; - dvc = NULL; - } - } - mod[idx] = mod_end; - - /* - * | SSI | SRC | - * -------------+-----+-----+ - * is_play | o | * | - * !is_play | * | o | - */ - if ((this == ssi) == (is_play)) { - *mod_from = mod[idx - 1]; - *mod_to = mod[idx]; - } else { - *mod_from = mod[0]; - *mod_to = mod[1]; - } - - dev_dbg(dev, "module connection (this is %s)\n", rsnd_mod_name(this)); - for (i = 0; i <= idx; i++) { - dev_dbg(dev, " %s%s\n", - rsnd_mod_name(mod[i] ? mod[i] : &mem), - (mod[i] == *mod_from) ? " from" : - (mod[i] == *mod_to) ? " to" : ""); - } -} - -static int rsnd_dma_alloc(struct rsnd_dai_stream *io, struct rsnd_mod *mod, - struct rsnd_mod **dma_mod) -{ - struct rsnd_mod *mod_from = NULL; - struct rsnd_mod *mod_to = NULL; - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_dma *dma; - struct rsnd_mod_ops *ops; - enum rsnd_mod_type type; - int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, - struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); - int is_play = rsnd_io_is_play(io); - int ret, dma_id; - - /* - * DMA failed. try to PIO mode - * see - * rsnd_ssi_fallback() - * rsnd_rdai_continuance_probe() - */ - if (!dmac) - return -EAGAIN; - - rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to); - - /* for Gen2 or later */ - if (mod_from && mod_to) { - ops = &rsnd_dmapp_ops; - attach = rsnd_dmapp_attach; - dma_id = dmac->dmapp_num; - type = RSND_MOD_AUDMAPP; - } else { - ops = &rsnd_dmaen_ops; - attach = rsnd_dmaen_attach; - dma_id = dmac->dmaen_num; - type = RSND_MOD_AUDMA; - } - - /* for Gen1, overwrite */ - if (rsnd_is_gen1(priv)) { - ops = &rsnd_dmaen_ops; - attach = rsnd_dmaen_attach; - dma_id = dmac->dmaen_num; - type = RSND_MOD_AUDMA; - } - - dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); - if (!dma) - return -ENOMEM; - - *dma_mod = rsnd_mod_get(dma); - - ret = rsnd_mod_init(priv, *dma_mod, ops, NULL, - type, dma_id); - if (ret < 0) - return ret; - - dev_dbg(dev, "%s %s -> %s\n", - rsnd_mod_name(*dma_mod), - rsnd_mod_name(mod_from ? mod_from : &mem), - rsnd_mod_name(mod_to ? mod_to : &mem)); - - ret = attach(io, dma, mod_from, mod_to); - if (ret < 0) - return ret; - - dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); - dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); - dma->mod_from = mod_from; - dma->mod_to = mod_to; - - return 0; -} - -int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, - struct rsnd_mod **dma_mod) -{ - if (!(*dma_mod)) { - int ret = rsnd_dma_alloc(io, mod, dma_mod); - - if (ret < 0) - return ret; - } - - return rsnd_dai_connect(*dma_mod, io, (*dma_mod)->type); -} - -int rsnd_dma_probe(struct rsnd_priv *priv) -{ - struct platform_device *pdev = rsnd_priv_to_pdev(priv); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_dma_ctrl *dmac; - struct resource *res; - - /* - * for Gen1 - */ - if (rsnd_is_gen1(priv)) - return 0; - - /* - * for Gen2 or later - */ - dmac = devm_kzalloc(dev, sizeof(*dmac), GFP_KERNEL); - if (!dmac) { - dev_err(dev, "dma allocate failed\n"); - return 0; /* it will be PIO mode */ - } - - /* for Gen4 doesn't have DMA-pp */ - if (rsnd_is_gen4(priv)) - goto audmapp_end; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audmapp"); - if (!res) { - dev_err(dev, "lack of audmapp in DT\n"); - return 0; /* it will be PIO mode */ - } - - dmac->dmapp_num = 0; - dmac->ppres = res->start; - dmac->ppbase = devm_ioremap_resource(dev, res); - if (IS_ERR(dmac->ppbase)) - return PTR_ERR(dmac->ppbase); -audmapp_end: - priv->dma = dmac; - - /* dummy mem mod for debug */ - return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, 0, 0); -} diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c deleted file mode 100644 index 16befcbc312c..000000000000 --- a/sound/soc/sh/rcar/dvc.c +++ /dev/null @@ -1,396 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas R-Car DVC support -// -// Copyright (C) 2014 Renesas Solutions Corp. -// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> - -/* - * Playback Volume - * amixer set "DVC Out" 100% - * - * Capture Volume - * amixer set "DVC In" 100% - * - * Playback Mute - * amixer set "DVC Out Mute" on - * - * Capture Mute - * amixer set "DVC In Mute" on - * - * Volume Ramp - * amixer set "DVC Out Ramp Up Rate" "0.125 dB/64 steps" - * amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps" - * amixer set "DVC Out Ramp" on - * aplay xxx.wav & - * amixer set "DVC Out" 80% // Volume Down - * amixer set "DVC Out" 100% // Volume Up - */ - -#include "rsnd.h" - -#define RSND_DVC_NAME_SIZE 16 - -#define DVC_NAME "dvc" - -struct rsnd_dvc { - struct rsnd_mod mod; - struct rsnd_kctrl_cfg_m volume; - struct rsnd_kctrl_cfg_m mute; - struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */ - struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */ - struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */ -}; - -#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id) -#define rsnd_dvc_nr(priv) ((priv)->dvc_nr) - -#define rsnd_mod_to_dvc(_mod) \ - container_of((_mod), struct rsnd_dvc, mod) - -#define for_each_rsnd_dvc(pos, priv, i) \ - for ((i) = 0; \ - ((i) < rsnd_dvc_nr(priv)) && \ - ((pos) = (struct rsnd_dvc *)(priv)->dvc + i); \ - i++) - -static void rsnd_dvc_activation(struct rsnd_mod *mod) -{ - rsnd_mod_write(mod, DVC_SWRSR, 0); - rsnd_mod_write(mod, DVC_SWRSR, 1); -} - -static void rsnd_dvc_halt(struct rsnd_mod *mod) -{ - rsnd_mod_write(mod, DVC_DVUIR, 1); - rsnd_mod_write(mod, DVC_SWRSR, 0); -} - -#define rsnd_dvc_get_vrpdr(dvc) (rsnd_kctrl_vals(dvc->rup) << 8 | \ - rsnd_kctrl_vals(dvc->rdown)) -#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (rsnd_kctrl_valm(dvc->volume, 0) >> 13)) - -static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); - u32 val[RSND_MAX_CHANNELS]; - int i; - - /* Enable Ramp */ - if (rsnd_kctrl_vals(dvc->ren)) - for (i = 0; i < RSND_MAX_CHANNELS; i++) - val[i] = rsnd_kctrl_max(dvc->volume); - else - for (i = 0; i < RSND_MAX_CHANNELS; i++) - val[i] = rsnd_kctrl_valm(dvc->volume, i); - - /* Enable Digital Volume */ - for (i = 0; i < RSND_MAX_CHANNELS; i++) - rsnd_mod_write(mod, DVC_VOLxR(i), val[i]); -} - -static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); - u32 adinr = 0; - u32 dvucr = 0; - u32 vrctr = 0; - u32 vrpdr = 0; - u32 vrdbr = 0; - - adinr = rsnd_get_adinr_bit(mod, io) | - rsnd_runtime_channel_after_ctu(io); - - /* Enable Digital Volume, Zero Cross Mute Mode */ - dvucr |= 0x101; - - /* Enable Ramp */ - if (rsnd_kctrl_vals(dvc->ren)) { - dvucr |= 0x10; - - /* - * FIXME !! - * use scale-downed Digital Volume - * as Volume Ramp - * 7F FFFF -> 3FF - */ - vrctr = 0xff; - vrpdr = rsnd_dvc_get_vrpdr(dvc); - vrdbr = rsnd_dvc_get_vrdbr(dvc); - } - - /* Initialize operation */ - rsnd_mod_write(mod, DVC_DVUIR, 1); - - /* General Information */ - rsnd_mod_write(mod, DVC_ADINR, adinr); - rsnd_mod_write(mod, DVC_DVUCR, dvucr); - - /* Volume Ramp Parameter */ - rsnd_mod_write(mod, DVC_VRCTR, vrctr); - rsnd_mod_write(mod, DVC_VRPDR, vrpdr); - rsnd_mod_write(mod, DVC_VRDBR, vrdbr); - - /* Digital Volume Function Parameter */ - rsnd_dvc_volume_parameter(io, mod); - - /* cancel operation */ - rsnd_mod_write(mod, DVC_DVUIR, 0); -} - -static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); - u32 zcmcr = 0; - u32 vrpdr = 0; - u32 vrdbr = 0; - int i; - - for (i = 0; i < rsnd_kctrl_size(dvc->mute); i++) - zcmcr |= (!!rsnd_kctrl_valm(dvc->mute, i)) << i; - - if (rsnd_kctrl_vals(dvc->ren)) { - vrpdr = rsnd_dvc_get_vrpdr(dvc); - vrdbr = rsnd_dvc_get_vrdbr(dvc); - } - - /* Disable DVC Register access */ - rsnd_mod_write(mod, DVC_DVUER, 0); - - /* Zero Cross Mute Function */ - rsnd_mod_write(mod, DVC_ZCMCR, zcmcr); - - /* Volume Ramp Function */ - rsnd_mod_write(mod, DVC_VRPDR, vrpdr); - rsnd_mod_write(mod, DVC_VRDBR, vrdbr); - /* add DVC_VRWTR here */ - - /* Digital Volume Function Parameter */ - rsnd_dvc_volume_parameter(io, mod); - - /* Enable DVC Register access */ - rsnd_mod_write(mod, DVC_DVUER, 1); -} - -static int rsnd_dvc_probe_(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - return rsnd_cmd_attach(io, rsnd_mod_id(mod)); -} - -static int rsnd_dvc_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int ret; - - ret = rsnd_mod_power_on(mod); - if (ret < 0) - return ret; - - rsnd_dvc_activation(mod); - - rsnd_dvc_volume_init(io, mod); - - rsnd_dvc_volume_update(io, mod); - - return 0; -} - -static int rsnd_dvc_quit(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - rsnd_dvc_halt(mod); - - rsnd_mod_power_off(mod); - - return 0; -} - -static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd) -{ - struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - int is_play = rsnd_io_is_play(io); - int channels = rsnd_rdai_channels_get(rdai); - int ret; - - /* Volume */ - ret = rsnd_kctrl_new_m(mod, io, rtd, - is_play ? - "DVC Out Playback Volume" : "DVC In Capture Volume", - rsnd_kctrl_accept_anytime, - rsnd_dvc_volume_update, - &dvc->volume, channels, - 0x00800000 - 1); - if (ret < 0) - return ret; - - /* Mute */ - ret = rsnd_kctrl_new_m(mod, io, rtd, - is_play ? - "DVC Out Mute Switch" : "DVC In Mute Switch", - rsnd_kctrl_accept_anytime, - rsnd_dvc_volume_update, - &dvc->mute, channels, - 1); - if (ret < 0) - return ret; - - /* Ramp */ - ret = rsnd_kctrl_new_s(mod, io, rtd, - is_play ? - "DVC Out Ramp Switch" : "DVC In Ramp Switch", - rsnd_kctrl_accept_anytime, - rsnd_dvc_volume_update, - &dvc->ren, 1); - if (ret < 0) - return ret; - - ret = rsnd_kctrl_new_e(mod, io, rtd, - is_play ? - "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate", - rsnd_kctrl_accept_anytime, - rsnd_dvc_volume_update, - &dvc->rup, - volume_ramp_rate, - VOLUME_RAMP_MAX_DVC); - if (ret < 0) - return ret; - - ret = rsnd_kctrl_new_e(mod, io, rtd, - is_play ? - "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate", - rsnd_kctrl_accept_anytime, - rsnd_dvc_volume_update, - &dvc->rdown, - volume_ramp_rate, - VOLUME_RAMP_MAX_DVC); - - if (ret < 0) - return ret; - - return 0; -} - -static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - - return rsnd_dma_request_channel(rsnd_dvc_of_node(priv), - DVC_NAME, mod, "tx"); -} - -#ifdef CONFIG_DEBUG_FS -static void rsnd_dvc_debug_info(struct seq_file *m, - struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, - 0xe00 + rsnd_mod_id(mod) * 0x100, 0x60); -} -#define DEBUG_INFO .debug_info = rsnd_dvc_debug_info -#else -#define DEBUG_INFO -#endif - -static struct rsnd_mod_ops rsnd_dvc_ops = { - .name = DVC_NAME, - .dma_req = rsnd_dvc_dma_req, - .probe = rsnd_dvc_probe_, - .init = rsnd_dvc_init, - .quit = rsnd_dvc_quit, - .pcm_new = rsnd_dvc_pcm_new, - .get_status = rsnd_mod_get_status, - DEBUG_INFO -}; - -struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) -{ - if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv))) - id = 0; - - return rsnd_mod_get(rsnd_dvc_get(priv, id)); -} - -int rsnd_dvc_probe(struct rsnd_priv *priv) -{ - struct device_node *node; - struct device_node *np; - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_dvc *dvc; - struct clk *clk; - char name[RSND_DVC_NAME_SIZE]; - int i, nr, ret; - - /* This driver doesn't support Gen1 at this point */ - if (rsnd_is_gen1(priv)) - return 0; - - node = rsnd_dvc_of_node(priv); - if (!node) - return 0; /* not used is not error */ - - nr = of_get_child_count(node); - if (!nr) { - ret = -EINVAL; - goto rsnd_dvc_probe_done; - } - - dvc = devm_kcalloc(dev, nr, sizeof(*dvc), GFP_KERNEL); - if (!dvc) { - ret = -ENOMEM; - goto rsnd_dvc_probe_done; - } - - priv->dvc_nr = nr; - priv->dvc = dvc; - - i = 0; - ret = 0; - for_each_child_of_node(node, np) { - dvc = rsnd_dvc_get(priv, i); - - snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d", - DVC_NAME, i); - - clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - of_node_put(np); - goto rsnd_dvc_probe_done; - } - - ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops, - clk, RSND_MOD_DVC, i); - if (ret) { - of_node_put(np); - goto rsnd_dvc_probe_done; - } - - i++; - } - -rsnd_dvc_probe_done: - of_node_put(node); - - return ret; -} - -void rsnd_dvc_remove(struct rsnd_priv *priv) -{ - struct rsnd_dvc *dvc; - int i; - - for_each_rsnd_dvc(dvc, priv, i) { - rsnd_mod_quit(rsnd_mod_get(dvc)); - } -} diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c deleted file mode 100644 index 86bdecc24956..000000000000 --- a/sound/soc/sh/rcar/gen.c +++ /dev/null @@ -1,562 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas R-Car Gen1 SRU/SSI support -// -// Copyright (C) 2013 Renesas Solutions Corp. -// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> - -/* - * #define DEBUG - * - * you can also add below in - * ${LINUX}/drivers/base/regmap/regmap.c - * for regmap debug - * - * #define LOG_DEVICE "xxxx.rcar_sound" - */ - -#include "rsnd.h" - -struct rsnd_gen { - struct rsnd_gen_ops *ops; - - /* RSND_BASE_MAX base */ - void __iomem *base[RSND_BASE_MAX]; - phys_addr_t res[RSND_BASE_MAX]; - struct regmap *regmap[RSND_BASE_MAX]; - - /* RSND_REG_MAX base */ - struct regmap_field *regs[REG_MAX]; - const char *reg_name[REG_MAX]; -}; - -#define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) -#define rsnd_reg_name(gen, id) ((gen)->reg_name[id]) - -struct rsnd_regmap_field_conf { - int idx; - unsigned int reg_offset; - unsigned int id_offset; - const char *reg_name; -}; - -#define RSND_REG_SET(id, offset, _id_offset, n) \ -{ \ - .idx = id, \ - .reg_offset = offset, \ - .id_offset = _id_offset, \ - .reg_name = n, \ -} -/* single address mapping */ -#define RSND_GEN_S_REG(id, offset) \ - RSND_REG_SET(id, offset, 0, #id) - -/* multi address mapping */ -#define RSND_GEN_M_REG(id, offset, _id_offset) \ - RSND_REG_SET(id, offset, _id_offset, #id) - -/* - * basic function - */ -static int rsnd_is_accessible_reg(struct rsnd_priv *priv, - struct rsnd_gen *gen, enum rsnd_reg reg) -{ - if (!gen->regs[reg]) { - struct device *dev = rsnd_priv_to_dev(priv); - - dev_err(dev, "unsupported register access %x\n", reg); - return 0; - } - - return 1; -} - -static int rsnd_mod_id_cmd(struct rsnd_mod *mod) -{ - if (mod->ops->id_cmd) - return mod->ops->id_cmd(mod); - - return rsnd_mod_id(mod); -} - -u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - u32 val; - - if (!rsnd_is_accessible_reg(priv, gen, reg)) - return 0; - - regmap_fields_read(gen->regs[reg], rsnd_mod_id_cmd(mod), &val); - - dev_dbg(dev, "r %s - %-18s (%4d) : %08x\n", - rsnd_mod_name(mod), - rsnd_reg_name(gen, reg), reg, val); - - return val; -} - -void rsnd_mod_write(struct rsnd_mod *mod, - enum rsnd_reg reg, u32 data) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - - if (!rsnd_is_accessible_reg(priv, gen, reg)) - return; - - regmap_fields_force_write(gen->regs[reg], rsnd_mod_id_cmd(mod), data); - - dev_dbg(dev, "w %s - %-18s (%4d) : %08x\n", - rsnd_mod_name(mod), - rsnd_reg_name(gen, reg), reg, data); -} - -void rsnd_mod_bset(struct rsnd_mod *mod, - enum rsnd_reg reg, u32 mask, u32 data) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - - if (!rsnd_is_accessible_reg(priv, gen, reg)) - return; - - regmap_fields_force_update_bits(gen->regs[reg], - rsnd_mod_id_cmd(mod), mask, data); - - dev_dbg(dev, "b %s - %-18s (%4d) : %08x/%08x\n", - rsnd_mod_name(mod), - rsnd_reg_name(gen, reg), reg, data, mask); - -} - -phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id) -{ - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - - return gen->res[reg_id]; -} - -#ifdef CONFIG_DEBUG_FS -void __iomem *rsnd_gen_get_base_addr(struct rsnd_priv *priv, int reg_id) -{ - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - - return gen->base[reg_id]; -} -#endif - -#define rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf) \ - _rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf, ARRAY_SIZE(conf)) -static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, - int id_size, - int reg_id, - const char *name, - const struct rsnd_regmap_field_conf *conf, - int conf_size) -{ - struct platform_device *pdev = rsnd_priv_to_pdev(priv); - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - struct device *dev = rsnd_priv_to_dev(priv); - struct resource *res; - struct regmap_config regc; - struct regmap_field *regs; - struct regmap *regmap; - struct reg_field regf; - void __iomem *base; - int i; - - memset(®c, 0, sizeof(regc)); - regc.reg_bits = 32; - regc.val_bits = 32; - regc.reg_stride = 4; - regc.name = name; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); - if (!res) - res = platform_get_resource(pdev, IORESOURCE_MEM, reg_id); - if (!res) - return -ENODEV; - - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - regmap = devm_regmap_init_mmio(dev, base, ®c); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - /* RSND_BASE_MAX base */ - gen->base[reg_id] = base; - gen->regmap[reg_id] = regmap; - gen->res[reg_id] = res->start; - - for (i = 0; i < conf_size; i++) { - - regf.reg = conf[i].reg_offset; - regf.id_offset = conf[i].id_offset; - regf.lsb = 0; - regf.msb = 31; - regf.id_size = id_size; - - regs = devm_regmap_field_alloc(dev, regmap, regf); - if (IS_ERR(regs)) - return PTR_ERR(regs); - - /* RSND_REG_MAX base */ - gen->regs[conf[i].idx] = regs; - gen->reg_name[conf[i].idx] = conf[i].reg_name; - } - - return 0; -} - -/* - * Gen4 - */ -static int rsnd_gen4_probe(struct rsnd_priv *priv) -{ - static const struct rsnd_regmap_field_conf conf_ssiu[] = { - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE0, 0x850), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE2, 0x858), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE4, 0x890), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE6, 0x898), - RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840), - RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848), - RSND_GEN_S_REG(SSI_SYS_STATUS4, 0x880), - RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888), - - RSND_GEN_S_REG(SSI_BUSIF0_MODE, 0x0), - RSND_GEN_S_REG(SSI_BUSIF0_ADINR, 0x4), - RSND_GEN_S_REG(SSI_BUSIF0_DALIGN, 0x8), - RSND_GEN_S_REG(SSI_BUSIF1_MODE, 0x20), - RSND_GEN_S_REG(SSI_BUSIF1_ADINR, 0x24), - RSND_GEN_S_REG(SSI_BUSIF1_DALIGN, 0x28), - RSND_GEN_S_REG(SSI_BUSIF2_MODE, 0x40), - RSND_GEN_S_REG(SSI_BUSIF2_ADINR, 0x44), - RSND_GEN_S_REG(SSI_BUSIF2_DALIGN, 0x48), - RSND_GEN_S_REG(SSI_BUSIF3_MODE, 0x60), - RSND_GEN_S_REG(SSI_BUSIF3_ADINR, 0x64), - RSND_GEN_S_REG(SSI_BUSIF3_DALIGN, 0x68), - RSND_GEN_S_REG(SSI_BUSIF4_MODE, 0x500), - RSND_GEN_S_REG(SSI_BUSIF4_ADINR, 0x504), - RSND_GEN_S_REG(SSI_BUSIF4_DALIGN, 0x508), - RSND_GEN_S_REG(SSI_BUSIF5_MODE, 0x520), - RSND_GEN_S_REG(SSI_BUSIF5_ADINR, 0x524), - RSND_GEN_S_REG(SSI_BUSIF5_DALIGN, 0x528), - RSND_GEN_S_REG(SSI_BUSIF6_MODE, 0x540), - RSND_GEN_S_REG(SSI_BUSIF6_ADINR, 0x544), - RSND_GEN_S_REG(SSI_BUSIF6_DALIGN, 0x548), - RSND_GEN_S_REG(SSI_BUSIF7_MODE, 0x560), - RSND_GEN_S_REG(SSI_BUSIF7_ADINR, 0x564), - RSND_GEN_S_REG(SSI_BUSIF7_DALIGN, 0x568), - RSND_GEN_S_REG(SSI_CTRL, 0x010), - RSND_GEN_S_REG(SSI_INT_ENABLE, 0x018), - RSND_GEN_S_REG(SSI_MODE, 0x00c), - RSND_GEN_S_REG(SSI_MODE2, 0xa0c), - }; - static const struct rsnd_regmap_field_conf conf_adg[] = { - RSND_GEN_S_REG(BRRA, 0x00), - RSND_GEN_S_REG(BRRB, 0x04), - RSND_GEN_S_REG(BRGCKR, 0x08), - RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), - }; - static const struct rsnd_regmap_field_conf conf_ssi[] = { - RSND_GEN_S_REG(SSICR, 0x00), - RSND_GEN_S_REG(SSISR, 0x04), - RSND_GEN_S_REG(SSITDR, 0x08), - RSND_GEN_S_REG(SSIRDR, 0x0c), - RSND_GEN_S_REG(SSIWSR, 0x20), - }; - static const struct rsnd_regmap_field_conf conf_sdmc[] = { - RSND_GEN_M_REG(SSI_BUSIF, 0x0, 0x8000), - }; - int ret_adg = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_ADG, "adg", conf_adg); - int ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_SSIU, "ssiu", conf_ssiu); - int ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_SSI, "ssi", conf_ssi); - int ret_sdmc = rsnd_gen_regmap_init(priv, 10, RSND_GEN4_SDMC, "sdmc", conf_sdmc); - - return ret_adg | ret_ssiu | ret_ssi | ret_sdmc; -} - -/* - * Gen2 - */ -static int rsnd_gen2_probe(struct rsnd_priv *priv) -{ - static const struct rsnd_regmap_field_conf conf_ssiu[] = { - RSND_GEN_S_REG(SSI_MODE0, 0x800), - RSND_GEN_S_REG(SSI_MODE1, 0x804), - RSND_GEN_S_REG(SSI_MODE2, 0x808), - RSND_GEN_S_REG(SSI_CONTROL, 0x810), - RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840), - RSND_GEN_S_REG(SSI_SYS_STATUS1, 0x844), - RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848), - RSND_GEN_S_REG(SSI_SYS_STATUS3, 0x84c), - RSND_GEN_S_REG(SSI_SYS_STATUS4, 0x880), - RSND_GEN_S_REG(SSI_SYS_STATUS5, 0x884), - RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888), - RSND_GEN_S_REG(SSI_SYS_STATUS7, 0x88c), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE0, 0x850), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE1, 0x854), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE2, 0x858), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE3, 0x85c), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE4, 0x890), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE5, 0x894), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE6, 0x898), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE7, 0x89c), - RSND_GEN_S_REG(HDMI0_SEL, 0x9e0), - RSND_GEN_S_REG(HDMI1_SEL, 0x9e4), - - /* FIXME: it needs SSI_MODE2/3 in the future */ - RSND_GEN_M_REG(SSI_BUSIF0_MODE, 0x0, 0x80), - RSND_GEN_M_REG(SSI_BUSIF0_ADINR, 0x4, 0x80), - RSND_GEN_M_REG(SSI_BUSIF0_DALIGN, 0x8, 0x80), - RSND_GEN_M_REG(SSI_BUSIF1_MODE, 0x20, 0x80), - RSND_GEN_M_REG(SSI_BUSIF1_ADINR, 0x24, 0x80), - RSND_GEN_M_REG(SSI_BUSIF1_DALIGN, 0x28, 0x80), - RSND_GEN_M_REG(SSI_BUSIF2_MODE, 0x40, 0x80), - RSND_GEN_M_REG(SSI_BUSIF2_ADINR, 0x44, 0x80), - RSND_GEN_M_REG(SSI_BUSIF2_DALIGN, 0x48, 0x80), - RSND_GEN_M_REG(SSI_BUSIF3_MODE, 0x60, 0x80), - RSND_GEN_M_REG(SSI_BUSIF3_ADINR, 0x64, 0x80), - RSND_GEN_M_REG(SSI_BUSIF3_DALIGN, 0x68, 0x80), - RSND_GEN_M_REG(SSI_BUSIF4_MODE, 0x500, 0x80), - RSND_GEN_M_REG(SSI_BUSIF4_ADINR, 0x504, 0x80), - RSND_GEN_M_REG(SSI_BUSIF4_DALIGN, 0x508, 0x80), - RSND_GEN_M_REG(SSI_BUSIF5_MODE, 0x520, 0x80), - RSND_GEN_M_REG(SSI_BUSIF5_ADINR, 0x524, 0x80), - RSND_GEN_M_REG(SSI_BUSIF5_DALIGN, 0x528, 0x80), - RSND_GEN_M_REG(SSI_BUSIF6_MODE, 0x540, 0x80), - RSND_GEN_M_REG(SSI_BUSIF6_ADINR, 0x544, 0x80), - RSND_GEN_M_REG(SSI_BUSIF6_DALIGN, 0x548, 0x80), - RSND_GEN_M_REG(SSI_BUSIF7_MODE, 0x560, 0x80), - RSND_GEN_M_REG(SSI_BUSIF7_ADINR, 0x564, 0x80), - RSND_GEN_M_REG(SSI_BUSIF7_DALIGN, 0x568, 0x80), - RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80), - RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), - RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), - RSND_GEN_S_REG(SSI9_BUSIF0_MODE, 0x48c), - RSND_GEN_S_REG(SSI9_BUSIF0_ADINR, 0x484), - RSND_GEN_S_REG(SSI9_BUSIF0_DALIGN, 0x488), - RSND_GEN_S_REG(SSI9_BUSIF1_MODE, 0x4a0), - RSND_GEN_S_REG(SSI9_BUSIF1_ADINR, 0x4a4), - RSND_GEN_S_REG(SSI9_BUSIF1_DALIGN, 0x4a8), - RSND_GEN_S_REG(SSI9_BUSIF2_MODE, 0x4c0), - RSND_GEN_S_REG(SSI9_BUSIF2_ADINR, 0x4c4), - RSND_GEN_S_REG(SSI9_BUSIF2_DALIGN, 0x4c8), - RSND_GEN_S_REG(SSI9_BUSIF3_MODE, 0x4e0), - RSND_GEN_S_REG(SSI9_BUSIF3_ADINR, 0x4e4), - RSND_GEN_S_REG(SSI9_BUSIF3_DALIGN, 0x4e8), - RSND_GEN_S_REG(SSI9_BUSIF4_MODE, 0xd80), - RSND_GEN_S_REG(SSI9_BUSIF4_ADINR, 0xd84), - RSND_GEN_S_REG(SSI9_BUSIF4_DALIGN, 0xd88), - RSND_GEN_S_REG(SSI9_BUSIF5_MODE, 0xda0), - RSND_GEN_S_REG(SSI9_BUSIF5_ADINR, 0xda4), - RSND_GEN_S_REG(SSI9_BUSIF5_DALIGN, 0xda8), - RSND_GEN_S_REG(SSI9_BUSIF6_MODE, 0xdc0), - RSND_GEN_S_REG(SSI9_BUSIF6_ADINR, 0xdc4), - RSND_GEN_S_REG(SSI9_BUSIF6_DALIGN, 0xdc8), - RSND_GEN_S_REG(SSI9_BUSIF7_MODE, 0xde0), - RSND_GEN_S_REG(SSI9_BUSIF7_ADINR, 0xde4), - RSND_GEN_S_REG(SSI9_BUSIF7_DALIGN, 0xde8), - }; - - static const struct rsnd_regmap_field_conf conf_scu[] = { - RSND_GEN_M_REG(SRC_I_BUSIF_MODE,0x0, 0x20), - RSND_GEN_M_REG(SRC_O_BUSIF_MODE,0x4, 0x20), - RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8, 0x20), - RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20), - RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20), - RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20), - RSND_GEN_M_REG(CMD_BUSIF_MODE, 0x184, 0x20), - RSND_GEN_M_REG(CMD_BUSIF_DALIGN,0x188, 0x20), - RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20), - RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20), - RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8), - RSND_GEN_S_REG(SCU_SYS_INT_EN0, 0x1cc), - RSND_GEN_S_REG(SCU_SYS_STATUS1, 0x1d0), - RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1d4), - RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40), - RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40), - RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40), - RSND_GEN_M_REG(SRC_IFSCR, 0x21c, 0x40), - RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40), - RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40), - RSND_GEN_M_REG(SRC_BSDSR, 0x22c, 0x40), - RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40), - RSND_GEN_M_REG(CTU_SWRSR, 0x500, 0x100), - RSND_GEN_M_REG(CTU_CTUIR, 0x504, 0x100), - RSND_GEN_M_REG(CTU_ADINR, 0x508, 0x100), - RSND_GEN_M_REG(CTU_CPMDR, 0x510, 0x100), - RSND_GEN_M_REG(CTU_SCMDR, 0x514, 0x100), - RSND_GEN_M_REG(CTU_SV00R, 0x518, 0x100), - RSND_GEN_M_REG(CTU_SV01R, 0x51c, 0x100), - RSND_GEN_M_REG(CTU_SV02R, 0x520, 0x100), - RSND_GEN_M_REG(CTU_SV03R, 0x524, 0x100), - RSND_GEN_M_REG(CTU_SV04R, 0x528, 0x100), - RSND_GEN_M_REG(CTU_SV05R, 0x52c, 0x100), - RSND_GEN_M_REG(CTU_SV06R, 0x530, 0x100), - RSND_GEN_M_REG(CTU_SV07R, 0x534, 0x100), - RSND_GEN_M_REG(CTU_SV10R, 0x538, 0x100), - RSND_GEN_M_REG(CTU_SV11R, 0x53c, 0x100), - RSND_GEN_M_REG(CTU_SV12R, 0x540, 0x100), - RSND_GEN_M_REG(CTU_SV13R, 0x544, 0x100), - RSND_GEN_M_REG(CTU_SV14R, 0x548, 0x100), - RSND_GEN_M_REG(CTU_SV15R, 0x54c, 0x100), - RSND_GEN_M_REG(CTU_SV16R, 0x550, 0x100), - RSND_GEN_M_REG(CTU_SV17R, 0x554, 0x100), - RSND_GEN_M_REG(CTU_SV20R, 0x558, 0x100), - RSND_GEN_M_REG(CTU_SV21R, 0x55c, 0x100), - RSND_GEN_M_REG(CTU_SV22R, 0x560, 0x100), - RSND_GEN_M_REG(CTU_SV23R, 0x564, 0x100), - RSND_GEN_M_REG(CTU_SV24R, 0x568, 0x100), - RSND_GEN_M_REG(CTU_SV25R, 0x56c, 0x100), - RSND_GEN_M_REG(CTU_SV26R, 0x570, 0x100), - RSND_GEN_M_REG(CTU_SV27R, 0x574, 0x100), - RSND_GEN_M_REG(CTU_SV30R, 0x578, 0x100), - RSND_GEN_M_REG(CTU_SV31R, 0x57c, 0x100), - RSND_GEN_M_REG(CTU_SV32R, 0x580, 0x100), - RSND_GEN_M_REG(CTU_SV33R, 0x584, 0x100), - RSND_GEN_M_REG(CTU_SV34R, 0x588, 0x100), - RSND_GEN_M_REG(CTU_SV35R, 0x58c, 0x100), - RSND_GEN_M_REG(CTU_SV36R, 0x590, 0x100), - RSND_GEN_M_REG(CTU_SV37R, 0x594, 0x100), - RSND_GEN_M_REG(MIX_SWRSR, 0xd00, 0x40), - RSND_GEN_M_REG(MIX_MIXIR, 0xd04, 0x40), - RSND_GEN_M_REG(MIX_ADINR, 0xd08, 0x40), - RSND_GEN_M_REG(MIX_MIXMR, 0xd10, 0x40), - RSND_GEN_M_REG(MIX_MVPDR, 0xd14, 0x40), - RSND_GEN_M_REG(MIX_MDBAR, 0xd18, 0x40), - RSND_GEN_M_REG(MIX_MDBBR, 0xd1c, 0x40), - RSND_GEN_M_REG(MIX_MDBCR, 0xd20, 0x40), - RSND_GEN_M_REG(MIX_MDBDR, 0xd24, 0x40), - RSND_GEN_M_REG(MIX_MDBER, 0xd28, 0x40), - RSND_GEN_M_REG(DVC_SWRSR, 0xe00, 0x100), - RSND_GEN_M_REG(DVC_DVUIR, 0xe04, 0x100), - RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100), - RSND_GEN_M_REG(DVC_DVUCR, 0xe10, 0x100), - RSND_GEN_M_REG(DVC_ZCMCR, 0xe14, 0x100), - RSND_GEN_M_REG(DVC_VRCTR, 0xe18, 0x100), - RSND_GEN_M_REG(DVC_VRPDR, 0xe1c, 0x100), - RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100), - RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100), - RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100), - RSND_GEN_M_REG(DVC_VOL2R, 0xe30, 0x100), - RSND_GEN_M_REG(DVC_VOL3R, 0xe34, 0x100), - RSND_GEN_M_REG(DVC_VOL4R, 0xe38, 0x100), - RSND_GEN_M_REG(DVC_VOL5R, 0xe3c, 0x100), - RSND_GEN_M_REG(DVC_VOL6R, 0xe40, 0x100), - RSND_GEN_M_REG(DVC_VOL7R, 0xe44, 0x100), - RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100), - }; - static const struct rsnd_regmap_field_conf conf_adg[] = { - RSND_GEN_S_REG(BRRA, 0x00), - RSND_GEN_S_REG(BRRB, 0x04), - RSND_GEN_S_REG(BRGCKR, 0x08), - RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), - RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), - RSND_GEN_S_REG(AUDIO_CLK_SEL2, 0x14), - RSND_GEN_S_REG(DIV_EN, 0x30), - RSND_GEN_S_REG(SRCIN_TIMSEL0, 0x34), - RSND_GEN_S_REG(SRCIN_TIMSEL1, 0x38), - RSND_GEN_S_REG(SRCIN_TIMSEL2, 0x3c), - RSND_GEN_S_REG(SRCIN_TIMSEL3, 0x40), - RSND_GEN_S_REG(SRCIN_TIMSEL4, 0x44), - RSND_GEN_S_REG(SRCOUT_TIMSEL0, 0x48), - RSND_GEN_S_REG(SRCOUT_TIMSEL1, 0x4c), - RSND_GEN_S_REG(SRCOUT_TIMSEL2, 0x50), - RSND_GEN_S_REG(SRCOUT_TIMSEL3, 0x54), - RSND_GEN_S_REG(SRCOUT_TIMSEL4, 0x58), - RSND_GEN_S_REG(CMDOUT_TIMSEL, 0x5c), - }; - static const struct rsnd_regmap_field_conf conf_ssi[] = { - RSND_GEN_M_REG(SSICR, 0x00, 0x40), - RSND_GEN_M_REG(SSISR, 0x04, 0x40), - RSND_GEN_M_REG(SSITDR, 0x08, 0x40), - RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40), - RSND_GEN_M_REG(SSIWSR, 0x20, 0x40), - }; - int ret_ssiu; - int ret_scu; - int ret_adg; - int ret_ssi; - - ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSIU, "ssiu", conf_ssiu); - ret_scu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SCU, "scu", conf_scu); - ret_adg = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_ADG, "adg", conf_adg); - ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SSI, "ssi", conf_ssi); - if (ret_ssiu < 0 || - ret_scu < 0 || - ret_adg < 0 || - ret_ssi < 0) - return ret_ssiu | ret_scu | ret_adg | ret_ssi; - - return 0; -} - -/* - * Gen1 - */ - -static int rsnd_gen1_probe(struct rsnd_priv *priv) -{ - static const struct rsnd_regmap_field_conf conf_adg[] = { - RSND_GEN_S_REG(BRRA, 0x00), - RSND_GEN_S_REG(BRRB, 0x04), - RSND_GEN_S_REG(BRGCKR, 0x08), - RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), - RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), - }; - static const struct rsnd_regmap_field_conf conf_ssi[] = { - RSND_GEN_M_REG(SSICR, 0x00, 0x40), - RSND_GEN_M_REG(SSISR, 0x04, 0x40), - RSND_GEN_M_REG(SSITDR, 0x08, 0x40), - RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40), - RSND_GEN_M_REG(SSIWSR, 0x20, 0x40), - }; - int ret_adg; - int ret_ssi; - - ret_adg = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, "adg", conf_adg); - ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, "ssi", conf_ssi); - if (ret_adg < 0 || - ret_ssi < 0) - return ret_adg | ret_ssi; - - return 0; -} - -/* - * Gen - */ -int rsnd_gen_probe(struct rsnd_priv *priv) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_gen *gen; - int ret; - - gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL); - if (!gen) - return -ENOMEM; - - priv->gen = gen; - - ret = -ENODEV; - if (rsnd_is_gen1(priv)) - ret = rsnd_gen1_probe(priv); - else if (rsnd_is_gen2(priv) || - rsnd_is_gen3(priv)) - ret = rsnd_gen2_probe(priv); - else if (rsnd_is_gen4(priv)) - ret = rsnd_gen4_probe(priv); - - if (ret < 0) - dev_err(dev, "unknown generation R-Car sound device\n"); - - return ret; -} diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c deleted file mode 100644 index 1de0e085804c..000000000000 --- a/sound/soc/sh/rcar/mix.c +++ /dev/null @@ -1,360 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// mix.c -// -// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> - -/* - * CTUn MIXn - * +------+ +------+ - * [SRC3 / SRC6] -> |CTU n0| -> [MIX n0| -> - * [SRC4 / SRC9] -> |CTU n1| -> [MIX n1| -> - * [SRC0 / SRC1] -> |CTU n2| -> [MIX n2| -> - * [SRC2 / SRC5] -> |CTU n3| -> [MIX n3| -> - * +------+ +------+ - * - * ex) - * DAI0 : playback = <&src0 &ctu02 &mix0 &dvc0 &ssi0>; - * DAI1 : playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>; - * - * MIX Volume - * amixer set "MIX",0 100% // DAI0 Volume - * amixer set "MIX",1 100% // DAI1 Volume - * - * Volume Ramp - * amixer set "MIX Ramp Up Rate" "0.125 dB/1 step" - * amixer set "MIX Ramp Down Rate" "4 dB/1 step" - * amixer set "MIX Ramp" on - * aplay xxx.wav & - * amixer set "MIX",0 80% // DAI0 Volume Down - * amixer set "MIX",1 100% // DAI1 Volume Up - */ - -#include "rsnd.h" - -#define MIX_NAME_SIZE 16 -#define MIX_NAME "mix" - -struct rsnd_mix { - struct rsnd_mod mod; - struct rsnd_kctrl_cfg_s volumeA; /* MDBAR */ - struct rsnd_kctrl_cfg_s volumeB; /* MDBBR */ - struct rsnd_kctrl_cfg_s volumeC; /* MDBCR */ - struct rsnd_kctrl_cfg_s volumeD; /* MDBDR */ - struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */ - struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */ - struct rsnd_kctrl_cfg_s rdw; /* Ramp Rate Down */ - u32 flags; -}; - -#define ONCE_KCTRL_INITIALIZED (1 << 0) -#define HAS_VOLA (1 << 1) -#define HAS_VOLB (1 << 2) -#define HAS_VOLC (1 << 3) -#define HAS_VOLD (1 << 4) - -#define VOL_MAX 0x3ff - -#define rsnd_mod_to_mix(_mod) \ - container_of((_mod), struct rsnd_mix, mod) - -#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id) -#define rsnd_mix_nr(priv) ((priv)->mix_nr) -#define for_each_rsnd_mix(pos, priv, i) \ - for ((i) = 0; \ - ((i) < rsnd_mix_nr(priv)) && \ - ((pos) = (struct rsnd_mix *)(priv)->mix + i); \ - i++) - -static void rsnd_mix_activation(struct rsnd_mod *mod) -{ - rsnd_mod_write(mod, MIX_SWRSR, 0); - rsnd_mod_write(mod, MIX_SWRSR, 1); -} - -static void rsnd_mix_halt(struct rsnd_mod *mod) -{ - rsnd_mod_write(mod, MIX_MIXIR, 1); - rsnd_mod_write(mod, MIX_SWRSR, 0); -} - -#define rsnd_mix_get_vol(mix, X) \ - rsnd_flags_has(mix, HAS_VOL##X) ? \ - (VOL_MAX - rsnd_kctrl_vals(mix->volume##X)) : 0 -static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_mix *mix = rsnd_mod_to_mix(mod); - u32 volA = rsnd_mix_get_vol(mix, A); - u32 volB = rsnd_mix_get_vol(mix, B); - u32 volC = rsnd_mix_get_vol(mix, C); - u32 volD = rsnd_mix_get_vol(mix, D); - - dev_dbg(dev, "MIX A/B/C/D = %02x/%02x/%02x/%02x\n", - volA, volB, volC, volD); - - rsnd_mod_write(mod, MIX_MDBAR, volA); - rsnd_mod_write(mod, MIX_MDBBR, volB); - rsnd_mod_write(mod, MIX_MDBCR, volC); - rsnd_mod_write(mod, MIX_MDBDR, volD); -} - -static void rsnd_mix_volume_init(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_mix *mix = rsnd_mod_to_mix(mod); - - rsnd_mod_write(mod, MIX_MIXIR, 1); - - /* General Information */ - rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io)); - - /* volume step */ - rsnd_mod_write(mod, MIX_MIXMR, rsnd_kctrl_vals(mix->ren)); - rsnd_mod_write(mod, MIX_MVPDR, rsnd_kctrl_vals(mix->rup) << 8 | - rsnd_kctrl_vals(mix->rdw)); - - /* common volume parameter */ - rsnd_mix_volume_parameter(io, mod); - - rsnd_mod_write(mod, MIX_MIXIR, 0); -} - -static void rsnd_mix_volume_update(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - /* Disable MIX dB setting */ - rsnd_mod_write(mod, MIX_MDBER, 0); - - /* common volume parameter */ - rsnd_mix_volume_parameter(io, mod); - - /* Enable MIX dB setting */ - rsnd_mod_write(mod, MIX_MDBER, 1); -} - -static int rsnd_mix_probe_(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - return rsnd_cmd_attach(io, rsnd_mod_id(mod)); -} - -static int rsnd_mix_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int ret; - - ret = rsnd_mod_power_on(mod); - if (ret < 0) - return ret; - - rsnd_mix_activation(mod); - - rsnd_mix_volume_init(io, mod); - - rsnd_mix_volume_update(io, mod); - - return 0; -} - -static int rsnd_mix_quit(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - rsnd_mix_halt(mod); - - rsnd_mod_power_off(mod); - - return 0; -} - -static int rsnd_mix_pcm_new(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_mix *mix = rsnd_mod_to_mix(mod); - struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); - struct rsnd_kctrl_cfg_s *volume; - int ret; - - switch (rsnd_mod_id(src_mod)) { - case 3: - case 6: /* MDBAR */ - volume = &mix->volumeA; - rsnd_flags_set(mix, HAS_VOLA); - break; - case 4: - case 9: /* MDBBR */ - volume = &mix->volumeB; - rsnd_flags_set(mix, HAS_VOLB); - break; - case 0: - case 1: /* MDBCR */ - volume = &mix->volumeC; - rsnd_flags_set(mix, HAS_VOLC); - break; - case 2: - case 5: /* MDBDR */ - volume = &mix->volumeD; - rsnd_flags_set(mix, HAS_VOLD); - break; - default: - dev_err(dev, "unknown SRC is connected\n"); - return -EINVAL; - } - - /* Volume */ - ret = rsnd_kctrl_new_s(mod, io, rtd, - "MIX Playback Volume", - rsnd_kctrl_accept_anytime, - rsnd_mix_volume_update, - volume, VOL_MAX); - if (ret < 0) - return ret; - rsnd_kctrl_vals(*volume) = VOL_MAX; - - if (rsnd_flags_has(mix, ONCE_KCTRL_INITIALIZED)) - return ret; - - /* Ramp */ - ret = rsnd_kctrl_new_s(mod, io, rtd, - "MIX Ramp Switch", - rsnd_kctrl_accept_anytime, - rsnd_mix_volume_update, - &mix->ren, 1); - if (ret < 0) - return ret; - - ret = rsnd_kctrl_new_e(mod, io, rtd, - "MIX Ramp Up Rate", - rsnd_kctrl_accept_anytime, - rsnd_mix_volume_update, - &mix->rup, - volume_ramp_rate, - VOLUME_RAMP_MAX_MIX); - if (ret < 0) - return ret; - - ret = rsnd_kctrl_new_e(mod, io, rtd, - "MIX Ramp Down Rate", - rsnd_kctrl_accept_anytime, - rsnd_mix_volume_update, - &mix->rdw, - volume_ramp_rate, - VOLUME_RAMP_MAX_MIX); - - rsnd_flags_set(mix, ONCE_KCTRL_INITIALIZED); - - return ret; -} - -#ifdef CONFIG_DEBUG_FS -static void rsnd_mix_debug_info(struct seq_file *m, - struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, - 0xd00 + rsnd_mod_id(mod) * 0x40, 0x30); -} -#define DEBUG_INFO .debug_info = rsnd_mix_debug_info -#else -#define DEBUG_INFO -#endif - -static struct rsnd_mod_ops rsnd_mix_ops = { - .name = MIX_NAME, - .probe = rsnd_mix_probe_, - .init = rsnd_mix_init, - .quit = rsnd_mix_quit, - .pcm_new = rsnd_mix_pcm_new, - .get_status = rsnd_mod_get_status, - DEBUG_INFO -}; - -struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) -{ - if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv))) - id = 0; - - return rsnd_mod_get(rsnd_mix_get(priv, id)); -} - -int rsnd_mix_probe(struct rsnd_priv *priv) -{ - struct device_node *node; - struct device_node *np; - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_mix *mix; - struct clk *clk; - char name[MIX_NAME_SIZE]; - int i, nr, ret; - - /* This driver doesn't support Gen1 at this point */ - if (rsnd_is_gen1(priv)) - return 0; - - node = rsnd_mix_of_node(priv); - if (!node) - return 0; /* not used is not error */ - - nr = of_get_child_count(node); - if (!nr) { - ret = -EINVAL; - goto rsnd_mix_probe_done; - } - - mix = devm_kcalloc(dev, nr, sizeof(*mix), GFP_KERNEL); - if (!mix) { - ret = -ENOMEM; - goto rsnd_mix_probe_done; - } - - priv->mix_nr = nr; - priv->mix = mix; - - i = 0; - ret = 0; - for_each_child_of_node(node, np) { - mix = rsnd_mix_get(priv, i); - - snprintf(name, MIX_NAME_SIZE, "%s.%d", - MIX_NAME, i); - - clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - of_node_put(np); - goto rsnd_mix_probe_done; - } - - ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops, - clk, RSND_MOD_MIX, i); - if (ret) { - of_node_put(np); - goto rsnd_mix_probe_done; - } - - i++; - } - -rsnd_mix_probe_done: - of_node_put(node); - - return ret; -} - -void rsnd_mix_remove(struct rsnd_priv *priv) -{ - struct rsnd_mix *mix; - int i; - - for_each_rsnd_mix(mix, priv, i) { - rsnd_mod_quit(rsnd_mod_get(mix)); - } -} diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h deleted file mode 100644 index da716b1f52e4..000000000000 --- a/sound/soc/sh/rcar/rsnd.h +++ /dev/null @@ -1,916 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas R-Car -// -// Copyright (C) 2013 Renesas Solutions Corp. -// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> - -#ifndef RSND_H -#define RSND_H - -#include <linux/clk.h> -#include <linux/device.h> -#include <linux/dma-mapping.h> -#include <linux/io.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/sh_dma.h> -#include <linux/workqueue.h> -#include <sound/soc.h> -#include <sound/pcm_params.h> - -#define RSND_GEN1_SRU 0 -#define RSND_GEN1_ADG 1 -#define RSND_GEN1_SSI 2 - -#define RSND_GEN2_SCU 0 -#define RSND_GEN2_ADG 1 -#define RSND_GEN2_SSIU 2 -#define RSND_GEN2_SSI 3 - -#define RSND_GEN4_ADG 0 -#define RSND_GEN4_SSIU 1 -#define RSND_GEN4_SSI 2 -#define RSND_GEN4_SDMC 3 - -#define RSND_BASE_MAX 4 - -/* - * pseudo register - * - * The register address offsets SRU/SCU/SSIU on Gen1/Gen2 are very different. - * This driver uses pseudo register in order to hide it. - * see gen1/gen2 for detail - */ -enum rsnd_reg { - /* SCU (MIX/CTU/DVC) */ - SRC_I_BUSIF_MODE, - SRC_O_BUSIF_MODE, - SRC_ROUTE_MODE0, - SRC_SWRSR, - SRC_SRCIR, - SRC_ADINR, - SRC_IFSCR, - SRC_IFSVR, - SRC_SRCCR, - SRC_CTRL, - SRC_BSDSR, - SRC_BSISR, - SRC_INT_ENABLE0, - SRC_BUSIF_DALIGN, - SRCIN_TIMSEL0, - SRCIN_TIMSEL1, - SRCIN_TIMSEL2, - SRCIN_TIMSEL3, - SRCIN_TIMSEL4, - SRCOUT_TIMSEL0, - SRCOUT_TIMSEL1, - SRCOUT_TIMSEL2, - SRCOUT_TIMSEL3, - SRCOUT_TIMSEL4, - SCU_SYS_STATUS0, - SCU_SYS_STATUS1, - SCU_SYS_INT_EN0, - SCU_SYS_INT_EN1, - CMD_CTRL, - CMD_BUSIF_MODE, - CMD_BUSIF_DALIGN, - CMD_ROUTE_SLCT, - CMDOUT_TIMSEL, - CTU_SWRSR, - CTU_CTUIR, - CTU_ADINR, - CTU_CPMDR, - CTU_SCMDR, - CTU_SV00R, - CTU_SV01R, - CTU_SV02R, - CTU_SV03R, - CTU_SV04R, - CTU_SV05R, - CTU_SV06R, - CTU_SV07R, - CTU_SV10R, - CTU_SV11R, - CTU_SV12R, - CTU_SV13R, - CTU_SV14R, - CTU_SV15R, - CTU_SV16R, - CTU_SV17R, - CTU_SV20R, - CTU_SV21R, - CTU_SV22R, - CTU_SV23R, - CTU_SV24R, - CTU_SV25R, - CTU_SV26R, - CTU_SV27R, - CTU_SV30R, - CTU_SV31R, - CTU_SV32R, - CTU_SV33R, - CTU_SV34R, - CTU_SV35R, - CTU_SV36R, - CTU_SV37R, - MIX_SWRSR, - MIX_MIXIR, - MIX_ADINR, - MIX_MIXMR, - MIX_MVPDR, - MIX_MDBAR, - MIX_MDBBR, - MIX_MDBCR, - MIX_MDBDR, - MIX_MDBER, - DVC_SWRSR, - DVC_DVUIR, - DVC_ADINR, - DVC_DVUCR, - DVC_ZCMCR, - DVC_VOL0R, - DVC_VOL1R, - DVC_VOL2R, - DVC_VOL3R, - DVC_VOL4R, - DVC_VOL5R, - DVC_VOL6R, - DVC_VOL7R, - DVC_DVUER, - DVC_VRCTR, - DVC_VRPDR, - DVC_VRDBR, - - /* ADG */ - BRRA, - BRRB, - BRGCKR, - DIV_EN, - AUDIO_CLK_SEL0, - AUDIO_CLK_SEL1, - AUDIO_CLK_SEL2, - - /* SSIU */ - SSI_MODE, - SSI_MODE0, - SSI_MODE1, - SSI_MODE2, - SSI_CONTROL, - SSI_CTRL, - SSI_BUSIF0_MODE, - SSI_BUSIF1_MODE, - SSI_BUSIF2_MODE, - SSI_BUSIF3_MODE, - SSI_BUSIF4_MODE, - SSI_BUSIF5_MODE, - SSI_BUSIF6_MODE, - SSI_BUSIF7_MODE, - SSI_BUSIF0_ADINR, - SSI_BUSIF1_ADINR, - SSI_BUSIF2_ADINR, - SSI_BUSIF3_ADINR, - SSI_BUSIF4_ADINR, - SSI_BUSIF5_ADINR, - SSI_BUSIF6_ADINR, - SSI_BUSIF7_ADINR, - SSI_BUSIF0_DALIGN, - SSI_BUSIF1_DALIGN, - SSI_BUSIF2_DALIGN, - SSI_BUSIF3_DALIGN, - SSI_BUSIF4_DALIGN, - SSI_BUSIF5_DALIGN, - SSI_BUSIF6_DALIGN, - SSI_BUSIF7_DALIGN, - SSI_INT_ENABLE, - SSI_SYS_STATUS0, - SSI_SYS_STATUS1, - SSI_SYS_STATUS2, - SSI_SYS_STATUS3, - SSI_SYS_STATUS4, - SSI_SYS_STATUS5, - SSI_SYS_STATUS6, - SSI_SYS_STATUS7, - SSI_SYS_INT_ENABLE0, - SSI_SYS_INT_ENABLE1, - SSI_SYS_INT_ENABLE2, - SSI_SYS_INT_ENABLE3, - SSI_SYS_INT_ENABLE4, - SSI_SYS_INT_ENABLE5, - SSI_SYS_INT_ENABLE6, - SSI_SYS_INT_ENABLE7, - SSI_BUSIF, - HDMI0_SEL, - HDMI1_SEL, - SSI9_BUSIF0_MODE, - SSI9_BUSIF1_MODE, - SSI9_BUSIF2_MODE, - SSI9_BUSIF3_MODE, - SSI9_BUSIF4_MODE, - SSI9_BUSIF5_MODE, - SSI9_BUSIF6_MODE, - SSI9_BUSIF7_MODE, - SSI9_BUSIF0_ADINR, - SSI9_BUSIF1_ADINR, - SSI9_BUSIF2_ADINR, - SSI9_BUSIF3_ADINR, - SSI9_BUSIF4_ADINR, - SSI9_BUSIF5_ADINR, - SSI9_BUSIF6_ADINR, - SSI9_BUSIF7_ADINR, - SSI9_BUSIF0_DALIGN, - SSI9_BUSIF1_DALIGN, - SSI9_BUSIF2_DALIGN, - SSI9_BUSIF3_DALIGN, - SSI9_BUSIF4_DALIGN, - SSI9_BUSIF5_DALIGN, - SSI9_BUSIF6_DALIGN, - SSI9_BUSIF7_DALIGN, - - /* SSI */ - SSICR, - SSISR, - SSITDR, - SSIRDR, - SSIWSR, - - REG_MAX, -}; -#define SRCIN_TIMSEL(i) (SRCIN_TIMSEL0 + (i)) -#define SRCOUT_TIMSEL(i) (SRCOUT_TIMSEL0 + (i)) -#define CTU_SVxxR(i, j) (CTU_SV00R + (i * 8) + (j)) -#define DVC_VOLxR(i) (DVC_VOL0R + (i)) -#define AUDIO_CLK_SEL(i) (AUDIO_CLK_SEL0 + (i)) -#define SSI_BUSIF_MODE(i) (SSI_BUSIF0_MODE + (i)) -#define SSI_BUSIF_ADINR(i) (SSI_BUSIF0_ADINR + (i)) -#define SSI_BUSIF_DALIGN(i) (SSI_BUSIF0_DALIGN + (i)) -#define SSI9_BUSIF_MODE(i) (SSI9_BUSIF0_MODE + (i)) -#define SSI9_BUSIF_ADINR(i) (SSI9_BUSIF0_ADINR + (i)) -#define SSI9_BUSIF_DALIGN(i) (SSI9_BUSIF0_DALIGN + (i)) -#define SSI_SYS_STATUS(i) (SSI_SYS_STATUS0 + (i)) -#define SSI_SYS_INT_ENABLE(i) (SSI_SYS_INT_ENABLE0 + (i)) - - -struct rsnd_priv; -struct rsnd_mod; -struct rsnd_dai; -struct rsnd_dai_stream; - -/* - * R-Car basic functions - */ -u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg); -void rsnd_mod_write(struct rsnd_mod *mod, enum rsnd_reg reg, u32 data); -void rsnd_mod_bset(struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data); -u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io); -u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); -u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod); - -/* - * R-Car DMA - */ -int rsnd_dma_attach(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, struct rsnd_mod **dma_mod); -int rsnd_dma_probe(struct rsnd_priv *priv); -struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name, - struct rsnd_mod *mod, char *x); - -/* - * R-Car sound mod - */ -enum rsnd_mod_type { - RSND_MOD_AUDMAPP, - RSND_MOD_AUDMA, - RSND_MOD_DVC, - RSND_MOD_MIX, - RSND_MOD_CTU, - RSND_MOD_CMD, - RSND_MOD_SRC, - RSND_MOD_SSIM3, /* SSI multi 3 */ - RSND_MOD_SSIM2, /* SSI multi 2 */ - RSND_MOD_SSIM1, /* SSI multi 1 */ - RSND_MOD_SSIP, /* SSI parent */ - RSND_MOD_SSI, - RSND_MOD_SSIU, - RSND_MOD_MAX, -}; - -struct rsnd_mod_ops { - char *name; - struct dma_chan* (*dma_req)(struct rsnd_dai_stream *io, - struct rsnd_mod *mod); - int (*probe)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*remove)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*init)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*quit)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*start)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*stop)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*irq)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv, int enable); - int (*pcm_new)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd); - int (*hw_params)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params); - int (*pointer)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - snd_pcm_uframes_t *pointer); - int (*fallback)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*prepare)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*cleanup)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*hw_free)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_pcm_substream *substream); - u32 *(*get_status)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - enum rsnd_mod_type type); - int (*id)(struct rsnd_mod *mod); - int (*id_sub)(struct rsnd_mod *mod); - int (*id_cmd)(struct rsnd_mod *mod); - -#ifdef CONFIG_DEBUG_FS - void (*debug_info)(struct seq_file *m, - struct rsnd_dai_stream *io, struct rsnd_mod *mod); -#endif -}; - -struct rsnd_dai_stream; -struct rsnd_mod { - int id; - enum rsnd_mod_type type; - struct rsnd_mod_ops *ops; - struct rsnd_priv *priv; - struct clk *clk; - u32 status; -}; -/* - * status - * - * 0xH000DCB0 - * - * B 0: init 1: quit - * C 0: start 1: stop - * D 0: hw_params 1: hw_free - * - * H is always called (see __rsnd_mod_call) - */ -#define __rsnd_mod_shift_init 4 -#define __rsnd_mod_shift_quit 4 -#define __rsnd_mod_shift_start 8 -#define __rsnd_mod_shift_stop 8 -#define __rsnd_mod_shift_hw_params 12 -#define __rsnd_mod_shift_hw_free 12 -#define __rsnd_mod_shift_probe 28 /* always called */ -#define __rsnd_mod_shift_remove 28 /* always called */ -#define __rsnd_mod_shift_irq 28 /* always called */ -#define __rsnd_mod_shift_pcm_new 28 /* always called */ -#define __rsnd_mod_shift_fallback 28 /* always called */ -#define __rsnd_mod_shift_pointer 28 /* always called */ -#define __rsnd_mod_shift_prepare 28 /* always called */ -#define __rsnd_mod_shift_cleanup 28 /* always called */ - -#define __rsnd_mod_add_probe 0 -#define __rsnd_mod_add_remove 0 -#define __rsnd_mod_add_prepare 0 -#define __rsnd_mod_add_cleanup 0 -#define __rsnd_mod_add_init 1 /* needs protect */ -#define __rsnd_mod_add_quit -1 /* needs protect */ -#define __rsnd_mod_add_start 1 /* needs protect */ -#define __rsnd_mod_add_stop -1 /* needs protect */ -#define __rsnd_mod_add_hw_params 1 /* needs protect */ -#define __rsnd_mod_add_hw_free -1 /* needs protect */ -#define __rsnd_mod_add_irq 0 -#define __rsnd_mod_add_pcm_new 0 -#define __rsnd_mod_add_fallback 0 -#define __rsnd_mod_add_pointer 0 - -#define __rsnd_mod_call_probe 0 -#define __rsnd_mod_call_remove 0 -#define __rsnd_mod_call_prepare 0 -#define __rsnd_mod_call_cleanup 0 -#define __rsnd_mod_call_init 0 /* needs protect */ -#define __rsnd_mod_call_quit 1 /* needs protect */ -#define __rsnd_mod_call_start 0 /* needs protect */ -#define __rsnd_mod_call_stop 1 /* needs protect */ -#define __rsnd_mod_call_hw_params 0 /* needs protect */ -#define __rsnd_mod_call_hw_free 1 /* needs protect */ -#define __rsnd_mod_call_irq 0 -#define __rsnd_mod_call_pcm_new 0 -#define __rsnd_mod_call_fallback 0 -#define __rsnd_mod_call_pointer 0 - -#define rsnd_mod_to_priv(mod) ((mod)->priv) -#define rsnd_mod_power_on(mod) clk_enable((mod)->clk) -#define rsnd_mod_power_off(mod) clk_disable((mod)->clk) -#define rsnd_mod_get(ip) (&(ip)->mod) - -int rsnd_mod_init(struct rsnd_priv *priv, - struct rsnd_mod *mod, - struct rsnd_mod_ops *ops, - struct clk *clk, - enum rsnd_mod_type type, - int id); -void rsnd_mod_quit(struct rsnd_mod *mod); -struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, - struct rsnd_mod *mod); -void rsnd_mod_interrupt(struct rsnd_mod *mod, - void (*callback)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io)); -u32 *rsnd_mod_get_status(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - enum rsnd_mod_type type); -int rsnd_mod_id(struct rsnd_mod *mod); -int rsnd_mod_id_raw(struct rsnd_mod *mod); -int rsnd_mod_id_sub(struct rsnd_mod *mod); -char *rsnd_mod_name(struct rsnd_mod *mod); -struct rsnd_mod *rsnd_mod_next(int *iterator, - struct rsnd_dai_stream *io, - enum rsnd_mod_type *array, - int array_size); -#define for_each_rsnd_mod(iterator, pos, io) \ - for (iterator = 0; \ - (pos = rsnd_mod_next(&iterator, io, NULL, 0)); iterator++) -#define for_each_rsnd_mod_arrays(iterator, pos, io, array, size) \ - for (iterator = 0; \ - (pos = rsnd_mod_next(&iterator, io, array, size)); iterator++) -#define for_each_rsnd_mod_array(iterator, pos, io, array) \ - for_each_rsnd_mod_arrays(iterator, pos, io, array, ARRAY_SIZE(array)) - -void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name, - struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), - struct device_node *node, - struct device_node *playback, - struct device_node *capture); -int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name); -int rsnd_node_fixed_index(struct device *dev, struct device_node *node, char *name, int idx); - -int rsnd_channel_normalization(int chan); -#define rsnd_runtime_channel_original(io) \ - rsnd_runtime_channel_original_with_params(io, NULL) -int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, - struct snd_pcm_hw_params *params); -#define rsnd_runtime_channel_after_ctu(io) \ - rsnd_runtime_channel_after_ctu_with_params(io, NULL) -int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, - struct snd_pcm_hw_params *params); -#define rsnd_runtime_channel_for_ssi(io) \ - rsnd_runtime_channel_for_ssi_with_params(io, NULL) -int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, - struct snd_pcm_hw_params *params); -int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io); -int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io); -int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io); - -/* - * DT - */ -#define rsnd_parse_of_node(priv, node) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node) -#define RSND_NODE_DAI "rcar_sound,dai" -#define RSND_NODE_SSI "rcar_sound,ssi" -#define RSND_NODE_SSIU "rcar_sound,ssiu" -#define RSND_NODE_SRC "rcar_sound,src" -#define RSND_NODE_CTU "rcar_sound,ctu" -#define RSND_NODE_MIX "rcar_sound,mix" -#define RSND_NODE_DVC "rcar_sound,dvc" - -/* - * R-Car sound DAI - */ -#define RSND_DAI_NAME_SIZE 16 -struct rsnd_dai_stream { - char name[RSND_DAI_NAME_SIZE]; - struct snd_pcm_substream *substream; - struct rsnd_mod *mod[RSND_MOD_MAX]; - struct rsnd_mod *dma; - struct rsnd_dai *rdai; - struct device *dmac_dev; /* for IPMMU */ - u32 converted_rate; /* converted sampling rate */ - int converted_chan; /* converted channels */ - u32 parent_ssi_status; - u32 flags; -}; - -/* flags */ -#define RSND_STREAM_HDMI0 (1 << 0) /* for HDMI0 */ -#define RSND_STREAM_HDMI1 (1 << 1) /* for HDMI1 */ -#define RSND_STREAM_TDM_SPLIT (1 << 2) /* for TDM split mode */ -#define RSND_HW_RULE_ERR (1 << 3) /* hw_rule error */ - -#define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) -#define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) -#define rsnd_io_to_mod_ssiu(io) rsnd_io_to_mod((io), RSND_MOD_SSIU) -#define rsnd_io_to_mod_ssip(io) rsnd_io_to_mod((io), RSND_MOD_SSIP) -#define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC) -#define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU) -#define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX) -#define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC) -#define rsnd_io_to_mod_cmd(io) rsnd_io_to_mod((io), RSND_MOD_CMD) -#define rsnd_io_to_rdai(io) ((io)->rdai) -#define rsnd_io_to_priv(io) (rsnd_rdai_to_priv(rsnd_io_to_rdai(io))) -#define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io) -#define rsnd_io_to_runtime(io) ((io)->substream ? \ - (io)->substream->runtime : NULL) -#define rsnd_io_converted_rate(io) ((io)->converted_rate) -#define rsnd_io_converted_chan(io) ((io)->converted_chan) -int rsnd_io_is_working(struct rsnd_dai_stream *io); - -struct rsnd_dai { - char name[RSND_DAI_NAME_SIZE]; - struct rsnd_dai_stream playback; - struct rsnd_dai_stream capture; - struct rsnd_priv *priv; - struct snd_pcm_hw_constraint_list constraint; - struct of_phandle_args dai_args; - - int max_channels; /* 2ch - 16ch */ - int ssi_lane; /* 1lane - 4lane */ - int chan_width; /* 16/24/32 bit width */ - - unsigned int clk_master:1; - unsigned int bit_clk_inv:1; - unsigned int frm_clk_inv:1; - unsigned int sys_delay:1; - unsigned int data_alignment:1; -}; - -#define rsnd_rdai_nr(priv) ((priv)->rdai_nr) -#define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master) -#define rsnd_rdai_to_priv(rdai) ((rdai)->priv) -#define for_each_rsnd_dai(rdai, priv, i) \ - for (i = 0; \ - (i < rsnd_rdai_nr(priv)) && \ - ((rdai) = rsnd_rdai_get(priv, i)); \ - i++) - -struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id); - -#define rsnd_rdai_channels_set(rdai, max_channels) \ - rsnd_rdai_channels_ctrl(rdai, max_channels) -#define rsnd_rdai_channels_get(rdai) \ - rsnd_rdai_channels_ctrl(rdai, 0) -int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai, - int max_channels); - -#define rsnd_rdai_ssi_lane_set(rdai, ssi_lane) \ - rsnd_rdai_ssi_lane_ctrl(rdai, ssi_lane) -#define rsnd_rdai_ssi_lane_get(rdai) \ - rsnd_rdai_ssi_lane_ctrl(rdai, 0) -int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, - int ssi_lane); - -#define rsnd_rdai_width_set(rdai, width) \ - rsnd_rdai_width_ctrl(rdai, width) -#define rsnd_rdai_width_get(rdai) \ - rsnd_rdai_width_ctrl(rdai, 0) -int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width); -void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io); -int rsnd_dai_connect(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - enum rsnd_mod_type type); - -/* - * R-Car Gen1/Gen2 - */ -int rsnd_gen_probe(struct rsnd_priv *priv); -void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, - struct rsnd_mod *mod, - enum rsnd_reg reg); -phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id); -#ifdef CONFIG_DEBUG_FS -void __iomem *rsnd_gen_get_base_addr(struct rsnd_priv *priv, int reg_id); -#endif - -/* - * R-Car ADG - */ -int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate); -int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod); -int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate); -int rsnd_adg_probe(struct rsnd_priv *priv); -void rsnd_adg_remove(struct rsnd_priv *priv); -int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod, - struct rsnd_dai_stream *io, - unsigned int in_rate, - unsigned int out_rate); -int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, - struct rsnd_dai_stream *io); -#define rsnd_adg_clk_enable(priv) rsnd_adg_clk_control(priv, 1) -#define rsnd_adg_clk_disable(priv) rsnd_adg_clk_control(priv, 0) -void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable); -void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m); - -/* - * R-Car sound priv - */ -struct rsnd_priv { - - struct platform_device *pdev; - spinlock_t lock; - unsigned long flags; -#define RSND_GEN_MASK (0xF << 0) -#define RSND_GEN1 (1 << 0) -#define RSND_GEN2 (2 << 0) -#define RSND_GEN3 (3 << 0) -#define RSND_GEN4 (4 << 0) -#define RSND_SOC_MASK (0xFF << 4) -#define RSND_SOC_E (1 << 4) /* E1/E2/E3 */ - - /* - * below value will be filled on rsnd_gen_probe() - */ - void *gen; - - /* - * below value will be filled on rsnd_adg_probe() - */ - void *adg; - - /* - * below value will be filled on rsnd_dma_probe() - */ - void *dma; - - /* - * below value will be filled on rsnd_ssi_probe() - */ - void *ssi; - int ssi_nr; - - /* - * below value will be filled on rsnd_ssiu_probe() - */ - void *ssiu; - int ssiu_nr; - - /* - * below value will be filled on rsnd_src_probe() - */ - void *src; - int src_nr; - - /* - * below value will be filled on rsnd_ctu_probe() - */ - void *ctu; - int ctu_nr; - - /* - * below value will be filled on rsnd_mix_probe() - */ - void *mix; - int mix_nr; - - /* - * below value will be filled on rsnd_dvc_probe() - */ - void *dvc; - int dvc_nr; - - /* - * below value will be filled on rsnd_cmd_probe() - */ - void *cmd; - int cmd_nr; - - /* - * below value will be filled on rsnd_dai_probe() - */ - struct snd_soc_dai_driver *daidrv; - struct rsnd_dai *rdai; - int rdai_nr; - -#define RSND_MAX_COMPONENT 3 - int component_dais[RSND_MAX_COMPONENT]; -}; - -#define rsnd_priv_to_pdev(priv) ((priv)->pdev) -#define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev)) - -#define rsnd_is_gen1(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1) -#define rsnd_is_gen2(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2) -#define rsnd_is_gen3(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN3) -#define rsnd_is_gen4(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN4) -#define rsnd_is_e3(priv) (((priv)->flags & \ - (RSND_GEN_MASK | RSND_SOC_MASK)) == \ - (RSND_GEN3 | RSND_SOC_E)) - -#define rsnd_flags_has(p, f) ((p)->flags & (f)) -#define rsnd_flags_set(p, f) ((p)->flags |= (f)) -#define rsnd_flags_del(p, f) ((p)->flags &= ~(f)) - -/* - * rsnd_kctrl - */ -struct rsnd_kctrl_cfg { - unsigned int max; - unsigned int size; - u32 *val; - const char * const *texts; - int (*accept)(struct rsnd_dai_stream *io); - void (*update)(struct rsnd_dai_stream *io, struct rsnd_mod *mod); - struct rsnd_dai_stream *io; - struct snd_card *card; - struct snd_kcontrol *kctrl; - struct rsnd_mod *mod; -}; - -#define RSND_MAX_CHANNELS 8 -struct rsnd_kctrl_cfg_m { - struct rsnd_kctrl_cfg cfg; - u32 val[RSND_MAX_CHANNELS]; -}; - -struct rsnd_kctrl_cfg_s { - struct rsnd_kctrl_cfg cfg; - u32 val; -}; -#define rsnd_kctrl_size(x) ((x).cfg.size) -#define rsnd_kctrl_max(x) ((x).cfg.max) -#define rsnd_kctrl_valm(x, i) ((x).val[i]) /* = (x).cfg.val[i] */ -#define rsnd_kctrl_vals(x) ((x).val) /* = (x).cfg.val[0] */ - -int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io); -int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io); -struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg); -struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg); -int rsnd_kctrl_new(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd, - const unsigned char *name, - int (*accept)(struct rsnd_dai_stream *io), - void (*update)(struct rsnd_dai_stream *io, - struct rsnd_mod *mod), - struct rsnd_kctrl_cfg *cfg, - const char * const *texts, - int size, - u32 max); - -#define rsnd_kctrl_new_m(mod, io, rtd, name, accept, update, cfg, size, max) \ - rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_m(cfg), \ - NULL, size, max) - -#define rsnd_kctrl_new_s(mod, io, rtd, name, accept, update, cfg, max) \ - rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \ - NULL, 1, max) - -#define rsnd_kctrl_new_e(mod, io, rtd, name, accept, update, cfg, texts, size) \ - rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \ - texts, 1, size) - -extern const char * const volume_ramp_rate[]; -#define VOLUME_RAMP_MAX_DVC (0x17 + 1) -#define VOLUME_RAMP_MAX_MIX (0x0a + 1) - -/* - * R-Car SSI - */ -int rsnd_ssi_probe(struct rsnd_priv *priv); -void rsnd_ssi_remove(struct rsnd_priv *priv); -struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); -int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); -u32 rsnd_ssi_multi_secondaries_runtime(struct rsnd_dai_stream *io); -int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); - -#define rsnd_ssi_is_pin_sharing(io) \ - __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) -int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); - -#define rsnd_ssi_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSI) -void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, - struct device_node *playback, - struct device_node *capture); -unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai, - int param1, int param2, int *idx); - -/* - * R-Car SSIU - */ -int rsnd_ssiu_attach(struct rsnd_dai_stream *io, - struct rsnd_mod *mod); -int rsnd_ssiu_probe(struct rsnd_priv *priv); -void rsnd_ssiu_remove(struct rsnd_priv *priv); -void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai, - struct device_node *playback, - struct device_node *capture); -#define rsnd_ssiu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSIU) -bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod); - -/* - * R-Car SRC - */ -int rsnd_src_probe(struct rsnd_priv *priv); -void rsnd_src_remove(struct rsnd_priv *priv); -struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); - -#define rsnd_src_get_in_rate(priv, io) rsnd_src_get_rate(priv, io, 1) -#define rsnd_src_get_out_rate(priv, io) rsnd_src_get_rate(priv, io, 0) -unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, - struct rsnd_dai_stream *io, - int is_in); - -#define rsnd_src_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SRC) -#define rsnd_parse_connect_src(rdai, playback, capture) \ - rsnd_parse_connect_common(rdai, "src", rsnd_src_mod_get, \ - rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \ - playback, capture) - -/* - * R-Car CTU - */ -int rsnd_ctu_probe(struct rsnd_priv *priv); -void rsnd_ctu_remove(struct rsnd_priv *priv); -struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU) -#define rsnd_parse_connect_ctu(rdai, playback, capture) \ - rsnd_parse_connect_common(rdai, "ctu", rsnd_ctu_mod_get, \ - rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \ - playback, capture) - -/* - * R-Car MIX - */ -int rsnd_mix_probe(struct rsnd_priv *priv); -void rsnd_mix_remove(struct rsnd_priv *priv); -struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX) -#define rsnd_parse_connect_mix(rdai, playback, capture) \ - rsnd_parse_connect_common(rdai, "mix", rsnd_mix_mod_get, \ - rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \ - playback, capture) - -/* - * R-Car DVC - */ -int rsnd_dvc_probe(struct rsnd_priv *priv); -void rsnd_dvc_remove(struct rsnd_priv *priv); -struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC) -#define rsnd_parse_connect_dvc(rdai, playback, capture) \ - rsnd_parse_connect_common(rdai, "dvc", rsnd_dvc_mod_get, \ - rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \ - playback, capture) - -/* - * R-Car CMD - */ -int rsnd_cmd_probe(struct rsnd_priv *priv); -void rsnd_cmd_remove(struct rsnd_priv *priv); -int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id); - -void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type); -#ifdef DEBUG -#define rsnd_mod_confirm_ssi(mssi) rsnd_mod_make_sure(mssi, RSND_MOD_SSI) -#define rsnd_mod_confirm_src(msrc) rsnd_mod_make_sure(msrc, RSND_MOD_SRC) -#define rsnd_mod_confirm_dvc(mdvc) rsnd_mod_make_sure(mdvc, RSND_MOD_DVC) -#else -#define rsnd_mod_confirm_ssi(mssi) -#define rsnd_mod_confirm_src(msrc) -#define rsnd_mod_confirm_dvc(mdvc) -#endif - -/* - * If you don't need interrupt status debug message, - * define RSND_DEBUG_NO_IRQ_STATUS as 1 on top of src.c/ssi.c - * - * #define RSND_DEBUG_NO_IRQ_STATUS 1 - */ -#define rsnd_print_irq_status(dev, param...) do { \ - if (!IS_BUILTIN(RSND_DEBUG_NO_IRQ_STATUS)) \ - dev_info(dev, param); \ -} while (0) - -#ifdef CONFIG_DEBUG_FS -int rsnd_debugfs_probe(struct snd_soc_component *component); -void rsnd_debugfs_reg_show(struct seq_file *m, phys_addr_t _addr, - void __iomem *base, int offset, int size); -void rsnd_debugfs_mod_reg_show(struct seq_file *m, struct rsnd_mod *mod, - int reg_id, int offset, int size); - -#else -#define rsnd_debugfs_probe NULL -#endif - -#endif /* RSND_H */ diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c deleted file mode 100644 index 3241a1bdc9ea..000000000000 --- a/sound/soc/sh/rcar/src.c +++ /dev/null @@ -1,736 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas R-Car SRC support -// -// Copyright (C) 2013 Renesas Solutions Corp. -// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> - -/* - * You can use Synchronous Sampling Rate Convert (if no DVC) - * - * amixer set "SRC Out Rate" on - * aplay xxx.wav & - * amixer set "SRC Out Rate" 96000 // convert rate to 96000Hz - * amixer set "SRC Out Rate" 22050 // convert rate to 22050Hz - */ - -/* - * you can enable below define if you don't need - * SSI interrupt status debug message when debugging - * see rsnd_print_irq_status() - * - * #define RSND_DEBUG_NO_IRQ_STATUS 1 - */ - -#include <linux/of_irq.h> -#include "rsnd.h" - -#define SRC_NAME "src" - -/* SCU_SYSTEM_STATUS0/1 */ -#define OUF_SRC(id) ((1 << (id + 16)) | (1 << id)) - -struct rsnd_src { - struct rsnd_mod mod; - struct rsnd_mod *dma; - struct rsnd_kctrl_cfg_s sen; /* sync convert enable */ - struct rsnd_kctrl_cfg_s sync; /* sync convert */ - int irq; -}; - -#define RSND_SRC_NAME_SIZE 16 - -#define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id) -#define rsnd_src_nr(priv) ((priv)->src_nr) -#define rsnd_src_sync_is_enabled(mod) (rsnd_mod_to_src(mod)->sen.val) - -#define rsnd_mod_to_src(_mod) \ - container_of((_mod), struct rsnd_src, mod) - -#define for_each_rsnd_src(pos, priv, i) \ - for ((i) = 0; \ - ((i) < rsnd_src_nr(priv)) && \ - ((pos) = (struct rsnd_src *)(priv)->src + i); \ - i++) - - -/* - * image of SRC (Sampling Rate Converter) - * - * 96kHz <-> +-----+ 48kHz +-----+ 48kHz +-------+ - * 48kHz <-> | SRC | <------> | SSI | <-----> | codec | - * 44.1kHz <-> +-----+ +-----+ +-------+ - * ... - * - */ - -static void rsnd_src_activation(struct rsnd_mod *mod) -{ - rsnd_mod_write(mod, SRC_SWRSR, 0); - rsnd_mod_write(mod, SRC_SWRSR, 1); -} - -static void rsnd_src_halt(struct rsnd_mod *mod) -{ - rsnd_mod_write(mod, SRC_SRCIR, 1); - rsnd_mod_write(mod, SRC_SWRSR, 0); -} - -static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - int is_play = rsnd_io_is_play(io); - - return rsnd_dma_request_channel(rsnd_src_of_node(priv), - SRC_NAME, mod, - is_play ? "rx" : "tx"); -} - -static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_src *src = rsnd_mod_to_src(mod); - u32 convert_rate; - - if (!runtime) - return 0; - - if (!rsnd_src_sync_is_enabled(mod)) - return rsnd_io_converted_rate(io); - - convert_rate = src->sync.val; - - if (!convert_rate) - convert_rate = rsnd_io_converted_rate(io); - - if (!convert_rate) - convert_rate = runtime->rate; - - return convert_rate; -} - -unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, - struct rsnd_dai_stream *io, - int is_in) -{ - struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - unsigned int rate = 0; - int is_play = rsnd_io_is_play(io); - - /* - * Playback - * runtime_rate -> [SRC] -> convert_rate - * - * Capture - * convert_rate -> [SRC] -> runtime_rate - */ - - if (is_play == is_in) - return runtime->rate; - - /* - * return convert rate if SRC is used, - * otherwise, return runtime->rate as usual - */ - if (src_mod) - rate = rsnd_src_convert_rate(io, src_mod); - - if (!rate) - rate = runtime->rate; - - return rate; -} - -static const u32 bsdsr_table_pattern1[] = { - 0x01800000, /* 6 - 1/6 */ - 0x01000000, /* 6 - 1/4 */ - 0x00c00000, /* 6 - 1/3 */ - 0x00800000, /* 6 - 1/2 */ - 0x00600000, /* 6 - 2/3 */ - 0x00400000, /* 6 - 1 */ -}; - -static const u32 bsdsr_table_pattern2[] = { - 0x02400000, /* 6 - 1/6 */ - 0x01800000, /* 6 - 1/4 */ - 0x01200000, /* 6 - 1/3 */ - 0x00c00000, /* 6 - 1/2 */ - 0x00900000, /* 6 - 2/3 */ - 0x00600000, /* 6 - 1 */ -}; - -static const u32 bsisr_table[] = { - 0x00100060, /* 6 - 1/6 */ - 0x00100040, /* 6 - 1/4 */ - 0x00100030, /* 6 - 1/3 */ - 0x00100020, /* 6 - 1/2 */ - 0x00100020, /* 6 - 2/3 */ - 0x00100020, /* 6 - 1 */ -}; - -static const u32 chan288888[] = { - 0x00000006, /* 1 to 2 */ - 0x000001fe, /* 1 to 8 */ - 0x000001fe, /* 1 to 8 */ - 0x000001fe, /* 1 to 8 */ - 0x000001fe, /* 1 to 8 */ - 0x000001fe, /* 1 to 8 */ -}; - -static const u32 chan244888[] = { - 0x00000006, /* 1 to 2 */ - 0x0000001e, /* 1 to 4 */ - 0x0000001e, /* 1 to 4 */ - 0x000001fe, /* 1 to 8 */ - 0x000001fe, /* 1 to 8 */ - 0x000001fe, /* 1 to 8 */ -}; - -static const u32 chan222222[] = { - 0x00000006, /* 1 to 2 */ - 0x00000006, /* 1 to 2 */ - 0x00000006, /* 1 to 2 */ - 0x00000006, /* 1 to 2 */ - 0x00000006, /* 1 to 2 */ - 0x00000006, /* 1 to 2 */ -}; - -static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - int is_play = rsnd_io_is_play(io); - int use_src = 0; - u32 fin, fout; - u32 ifscr, fsrate, adinr; - u32 cr, route; - u32 i_busif, o_busif, tmp; - const u32 *bsdsr_table; - const u32 *chptn; - uint ratio; - int chan; - int idx; - - if (!runtime) - return; - - fin = rsnd_src_get_in_rate(priv, io); - fout = rsnd_src_get_out_rate(priv, io); - - chan = rsnd_runtime_channel_original(io); - - /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ - if (fin == fout) - ratio = 0; - else if (fin > fout) - ratio = 100 * fin / fout; - else - ratio = 100 * fout / fin; - - if (ratio > 600) { - dev_err(dev, "FSO/FSI ratio error\n"); - return; - } - - use_src = (fin != fout) | rsnd_src_sync_is_enabled(mod); - - /* - * SRC_ADINR - */ - adinr = rsnd_get_adinr_bit(mod, io) | chan; - - /* - * SRC_IFSCR / SRC_IFSVR - */ - ifscr = 0; - fsrate = 0; - if (use_src) { - u64 n; - - ifscr = 1; - n = (u64)0x0400000 * fin; - do_div(n, fout); - fsrate = n; - } - - /* - * SRC_SRCCR / SRC_ROUTE_MODE0 - */ - cr = 0x00011110; - route = 0x0; - if (use_src) { - route = 0x1; - - if (rsnd_src_sync_is_enabled(mod)) { - cr |= 0x1; - route |= rsnd_io_is_play(io) ? - (0x1 << 24) : (0x1 << 25); - } - } - - /* - * SRC_BSDSR / SRC_BSISR - * - * see - * Combination of Register Setting Related to - * FSO/FSI Ratio and Channel, Latency - */ - switch (rsnd_mod_id(mod)) { - case 0: - chptn = chan288888; - bsdsr_table = bsdsr_table_pattern1; - break; - case 1: - case 3: - case 4: - chptn = chan244888; - bsdsr_table = bsdsr_table_pattern1; - break; - case 2: - case 9: - chptn = chan222222; - bsdsr_table = bsdsr_table_pattern1; - break; - case 5: - case 6: - case 7: - case 8: - chptn = chan222222; - bsdsr_table = bsdsr_table_pattern2; - break; - default: - goto convert_rate_err; - } - - /* - * E3 need to overwrite - */ - if (rsnd_is_e3(priv)) - switch (rsnd_mod_id(mod)) { - case 0: - case 4: - chptn = chan222222; - } - - for (idx = 0; idx < ARRAY_SIZE(chan222222); idx++) - if (chptn[idx] & (1 << chan)) - break; - - if (chan > 8 || - idx >= ARRAY_SIZE(chan222222)) - goto convert_rate_err; - - /* BUSIF_MODE */ - tmp = rsnd_get_busif_shift(io, mod); - i_busif = ( is_play ? tmp : 0) | 1; - o_busif = (!is_play ? tmp : 0) | 1; - - rsnd_mod_write(mod, SRC_ROUTE_MODE0, route); - - rsnd_mod_write(mod, SRC_SRCIR, 1); /* initialize */ - rsnd_mod_write(mod, SRC_ADINR, adinr); - rsnd_mod_write(mod, SRC_IFSCR, ifscr); - rsnd_mod_write(mod, SRC_IFSVR, fsrate); - rsnd_mod_write(mod, SRC_SRCCR, cr); - rsnd_mod_write(mod, SRC_BSDSR, bsdsr_table[idx]); - rsnd_mod_write(mod, SRC_BSISR, bsisr_table[idx]); - rsnd_mod_write(mod, SRC_SRCIR, 0); /* cancel initialize */ - - rsnd_mod_write(mod, SRC_I_BUSIF_MODE, i_busif); - rsnd_mod_write(mod, SRC_O_BUSIF_MODE, o_busif); - - rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); - - rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout); - - return; - -convert_rate_err: - dev_err(dev, "unknown BSDSR/BSDIR settings\n"); -} - -static int rsnd_src_irq(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv, - int enable) -{ - struct rsnd_src *src = rsnd_mod_to_src(mod); - u32 sys_int_val, int_val, sys_int_mask; - int irq = src->irq; - int id = rsnd_mod_id(mod); - - sys_int_val = - sys_int_mask = OUF_SRC(id); - int_val = 0x3300; - - /* - * IRQ is not supported on non-DT - * see - * rsnd_src_probe_() - */ - if ((irq <= 0) || !enable) { - sys_int_val = 0; - int_val = 0; - } - - /* - * WORKAROUND - * - * ignore over flow error when rsnd_src_sync_is_enabled() - */ - if (rsnd_src_sync_is_enabled(mod)) - sys_int_val = sys_int_val & 0xffff; - - rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val); - rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val); - rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val); - - return 0; -} - -static void rsnd_src_status_clear(struct rsnd_mod *mod) -{ - u32 val = OUF_SRC(rsnd_mod_id(mod)); - - rsnd_mod_write(mod, SCU_SYS_STATUS0, val); - rsnd_mod_write(mod, SCU_SYS_STATUS1, val); -} - -static bool rsnd_src_error_occurred(struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - u32 val0, val1; - u32 status0, status1; - bool ret = false; - - val0 = val1 = OUF_SRC(rsnd_mod_id(mod)); - - /* - * WORKAROUND - * - * ignore over flow error when rsnd_src_sync_is_enabled() - */ - if (rsnd_src_sync_is_enabled(mod)) - val0 = val0 & 0xffff; - - status0 = rsnd_mod_read(mod, SCU_SYS_STATUS0); - status1 = rsnd_mod_read(mod, SCU_SYS_STATUS1); - if ((status0 & val0) || (status1 & val1)) { - rsnd_print_irq_status(dev, "%s err status : 0x%08x, 0x%08x\n", - rsnd_mod_name(mod), status0, status1); - - ret = true; - } - - return ret; -} - -static int rsnd_src_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - u32 val; - - /* - * WORKAROUND - * - * Enable SRC output if you want to use sync convert together with DVC - */ - val = (rsnd_io_to_mod_dvc(io) && !rsnd_src_sync_is_enabled(mod)) ? - 0x01 : 0x11; - - rsnd_mod_write(mod, SRC_CTRL, val); - - return 0; -} - -static int rsnd_src_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - rsnd_mod_write(mod, SRC_CTRL, 0); - - return 0; -} - -static int rsnd_src_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_src *src = rsnd_mod_to_src(mod); - int ret; - - /* reset sync convert_rate */ - src->sync.val = 0; - - ret = rsnd_mod_power_on(mod); - if (ret < 0) - return ret; - - rsnd_src_activation(mod); - - rsnd_src_set_convert_rate(io, mod); - - rsnd_src_status_clear(mod); - - return 0; -} - -static int rsnd_src_quit(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_src *src = rsnd_mod_to_src(mod); - - rsnd_src_halt(mod); - - rsnd_mod_power_off(mod); - - /* reset sync convert_rate */ - src->sync.val = 0; - - return 0; -} - -static void __rsnd_src_interrupt(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - bool stop = false; - - spin_lock(&priv->lock); - - /* ignore all cases if not working */ - if (!rsnd_io_is_working(io)) - goto rsnd_src_interrupt_out; - - if (rsnd_src_error_occurred(mod)) - stop = true; - - rsnd_src_status_clear(mod); -rsnd_src_interrupt_out: - - spin_unlock(&priv->lock); - - if (stop) - snd_pcm_stop_xrun(io->substream); -} - -static irqreturn_t rsnd_src_interrupt(int irq, void *data) -{ - struct rsnd_mod *mod = data; - - rsnd_mod_interrupt(mod, __rsnd_src_interrupt); - - return IRQ_HANDLED; -} - -static int rsnd_src_probe_(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_src *src = rsnd_mod_to_src(mod); - struct device *dev = rsnd_priv_to_dev(priv); - int irq = src->irq; - int ret; - - if (irq > 0) { - /* - * IRQ is not supported on non-DT - * see - * rsnd_src_irq() - */ - ret = devm_request_irq(dev, irq, - rsnd_src_interrupt, - IRQF_SHARED, - dev_name(dev), mod); - if (ret) - return ret; - } - - ret = rsnd_dma_attach(io, mod, &src->dma); - - return ret; -} - -static int rsnd_src_pcm_new(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd) -{ - struct rsnd_src *src = rsnd_mod_to_src(mod); - int ret; - - /* - * enable SRC sync convert if possible - */ - - /* - * It can't use SRC Synchronous convert - * when Capture if it uses CMD - */ - if (rsnd_io_to_mod_cmd(io) && !rsnd_io_is_play(io)) - return 0; - - /* - * enable sync convert - */ - ret = rsnd_kctrl_new_s(mod, io, rtd, - rsnd_io_is_play(io) ? - "SRC Out Rate Switch" : - "SRC In Rate Switch", - rsnd_kctrl_accept_anytime, - rsnd_src_set_convert_rate, - &src->sen, 1); - if (ret < 0) - return ret; - - ret = rsnd_kctrl_new_s(mod, io, rtd, - rsnd_io_is_play(io) ? - "SRC Out Rate" : - "SRC In Rate", - rsnd_kctrl_accept_runtime, - rsnd_src_set_convert_rate, - &src->sync, 192000); - - return ret; -} - -#ifdef CONFIG_DEBUG_FS -static void rsnd_src_debug_info(struct seq_file *m, - struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, - rsnd_mod_id(mod) * 0x20, 0x20); - seq_puts(m, "\n"); - rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, - 0x1c0, 0x20); - seq_puts(m, "\n"); - rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SCU, - 0x200 + rsnd_mod_id(mod) * 0x40, 0x40); -} -#define DEBUG_INFO .debug_info = rsnd_src_debug_info -#else -#define DEBUG_INFO -#endif - -static struct rsnd_mod_ops rsnd_src_ops = { - .name = SRC_NAME, - .dma_req = rsnd_src_dma_req, - .probe = rsnd_src_probe_, - .init = rsnd_src_init, - .quit = rsnd_src_quit, - .start = rsnd_src_start, - .stop = rsnd_src_stop, - .irq = rsnd_src_irq, - .pcm_new = rsnd_src_pcm_new, - .get_status = rsnd_mod_get_status, - DEBUG_INFO -}; - -struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) -{ - if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv))) - id = 0; - - return rsnd_mod_get(rsnd_src_get(priv, id)); -} - -int rsnd_src_probe(struct rsnd_priv *priv) -{ - struct device_node *node; - struct device_node *np; - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_src *src; - struct clk *clk; - char name[RSND_SRC_NAME_SIZE]; - int i, nr, ret; - - /* This driver doesn't support Gen1 at this point */ - if (rsnd_is_gen1(priv)) - return 0; - - node = rsnd_src_of_node(priv); - if (!node) - return 0; /* not used is not error */ - - nr = rsnd_node_count(priv, node, SRC_NAME); - if (!nr) { - ret = -EINVAL; - goto rsnd_src_probe_done; - } - - src = devm_kcalloc(dev, nr, sizeof(*src), GFP_KERNEL); - if (!src) { - ret = -ENOMEM; - goto rsnd_src_probe_done; - } - - priv->src_nr = nr; - priv->src = src; - - i = 0; - for_each_child_of_node(node, np) { - if (!of_device_is_available(np)) - goto skip; - - i = rsnd_node_fixed_index(dev, np, SRC_NAME, i); - if (i < 0) { - ret = -EINVAL; - of_node_put(np); - goto rsnd_src_probe_done; - } - - src = rsnd_src_get(priv, i); - - snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d", - SRC_NAME, i); - - src->irq = irq_of_parse_and_map(np, 0); - if (!src->irq) { - ret = -EINVAL; - of_node_put(np); - goto rsnd_src_probe_done; - } - - clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - of_node_put(np); - goto rsnd_src_probe_done; - } - - ret = rsnd_mod_init(priv, rsnd_mod_get(src), - &rsnd_src_ops, clk, RSND_MOD_SRC, i); - if (ret) { - of_node_put(np); - goto rsnd_src_probe_done; - } - -skip: - i++; - } - - ret = 0; - -rsnd_src_probe_done: - of_node_put(node); - - return ret; -} - -void rsnd_src_remove(struct rsnd_priv *priv) -{ - struct rsnd_src *src; - int i; - - for_each_rsnd_src(src, priv, i) { - rsnd_mod_quit(rsnd_mod_get(src)); - } -} diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c deleted file mode 100644 index 0a46aa1975fa..000000000000 --- a/sound/soc/sh/rcar/ssi.c +++ /dev/null @@ -1,1260 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas R-Car SSIU/SSI support -// -// Copyright (C) 2013 Renesas Solutions Corp. -// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> -// -// Based on fsi.c -// Kuninori Morimoto <morimoto.kuninori@renesas.com> - -/* - * you can enable below define if you don't need - * SSI interrupt status debug message when debugging - * see rsnd_print_irq_status() - * - * #define RSND_DEBUG_NO_IRQ_STATUS 1 - */ - -#include <sound/simple_card_utils.h> -#include <linux/of.h> -#include <linux/of_irq.h> -#include <linux/delay.h> -#include "rsnd.h" -#define RSND_SSI_NAME_SIZE 16 - -/* - * SSICR - */ -#define FORCE (1u << 31) /* Fixed */ -#define DMEN (1u << 28) /* DMA Enable */ -#define UIEN (1u << 27) /* Underflow Interrupt Enable */ -#define OIEN (1u << 26) /* Overflow Interrupt Enable */ -#define IIEN (1u << 25) /* Idle Mode Interrupt Enable */ -#define DIEN (1u << 24) /* Data Interrupt Enable */ -#define CHNL_4 (1u << 22) /* Channels */ -#define CHNL_6 (2u << 22) /* Channels */ -#define CHNL_8 (3u << 22) /* Channels */ -#define DWL_MASK (7u << 19) /* Data Word Length mask */ -#define DWL_8 (0u << 19) /* Data Word Length */ -#define DWL_16 (1u << 19) /* Data Word Length */ -#define DWL_18 (2u << 19) /* Data Word Length */ -#define DWL_20 (3u << 19) /* Data Word Length */ -#define DWL_22 (4u << 19) /* Data Word Length */ -#define DWL_24 (5u << 19) /* Data Word Length */ -#define DWL_32 (6u << 19) /* Data Word Length */ - -/* - * System word length - */ -#define SWL_16 (1 << 16) /* R/W System Word Length */ -#define SWL_24 (2 << 16) /* R/W System Word Length */ -#define SWL_32 (3 << 16) /* R/W System Word Length */ - -#define SCKD (1 << 15) /* Serial Bit Clock Direction */ -#define SWSD (1 << 14) /* Serial WS Direction */ -#define SCKP (1 << 13) /* Serial Bit Clock Polarity */ -#define SWSP (1 << 12) /* Serial WS Polarity */ -#define SDTA (1 << 10) /* Serial Data Alignment */ -#define PDTA (1 << 9) /* Parallel Data Alignment */ -#define DEL (1 << 8) /* Serial Data Delay */ -#define CKDV(v) (v << 4) /* Serial Clock Division Ratio */ -#define TRMD (1 << 1) /* Transmit/Receive Mode Select */ -#define EN (1 << 0) /* SSI Module Enable */ - -/* - * SSISR - */ -#define UIRQ (1 << 27) /* Underflow Error Interrupt Status */ -#define OIRQ (1 << 26) /* Overflow Error Interrupt Status */ -#define IIRQ (1 << 25) /* Idle Mode Interrupt Status */ -#define DIRQ (1 << 24) /* Data Interrupt Status Flag */ - -/* - * SSIWSR - */ -#define CONT (1 << 8) /* WS Continue Function */ -#define WS_MODE (1 << 0) /* WS Mode */ - -#define SSI_NAME "ssi" - -struct rsnd_ssi { - struct rsnd_mod mod; - - u32 flags; - u32 cr_own; - u32 cr_clk; - u32 cr_mode; - u32 cr_en; - u32 wsr; - int chan; - int rate; - int irq; - unsigned int usrcnt; - - /* for PIO */ - int byte_pos; - int byte_per_period; - int next_period_byte; -}; - -/* flags */ -#define RSND_SSI_CLK_PIN_SHARE (1 << 0) -#define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */ -#define RSND_SSI_PROBED (1 << 2) - -#define for_each_rsnd_ssi(pos, priv, i) \ - for (i = 0; \ - (i < rsnd_ssi_nr(priv)) && \ - ((pos) = ((struct rsnd_ssi *)(priv)->ssi + i)); \ - i++) - -#define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id) -#define rsnd_ssi_nr(priv) ((priv)->ssi_nr) -#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) -#define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) -#define rsnd_ssi_is_multi_secondary(mod, io) \ - (rsnd_ssi_multi_secondaries(io) & (1 << rsnd_mod_id(mod))) -#define rsnd_ssi_is_run_mods(mod, io) \ - (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod))) -#define rsnd_ssi_can_output_clk(mod) (!__rsnd_ssi_is_pin_sharing(mod)) - -int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) -{ - struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - int use_busif = 0; - - if (!rsnd_ssi_is_dma_mode(mod)) - return 0; - - if (!(rsnd_flags_has(ssi, RSND_SSI_NO_BUSIF))) - use_busif = 1; - if (rsnd_io_to_mod_src(io)) - use_busif = 1; - - return use_busif; -} - -static void rsnd_ssi_status_clear(struct rsnd_mod *mod) -{ - rsnd_mod_write(mod, SSISR, 0); -} - -static u32 rsnd_ssi_status_get(struct rsnd_mod *mod) -{ - return rsnd_mod_read(mod, SSISR); -} - -static void rsnd_ssi_status_check(struct rsnd_mod *mod, - u32 bit) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - u32 status; - int i; - - for (i = 0; i < 1024; i++) { - status = rsnd_ssi_status_get(mod); - if (status & bit) - return; - - udelay(5); - } - - dev_warn(dev, "%s status check failed\n", rsnd_mod_name(mod)); -} - -static u32 rsnd_ssi_multi_secondaries(struct rsnd_dai_stream *io) -{ - static const enum rsnd_mod_type types[] = { - RSND_MOD_SSIM1, - RSND_MOD_SSIM2, - RSND_MOD_SSIM3, - }; - int i, mask; - - mask = 0; - for (i = 0; i < ARRAY_SIZE(types); i++) { - struct rsnd_mod *mod = rsnd_io_to_mod(io, types[i]); - - if (!mod) - continue; - - mask |= 1 << rsnd_mod_id(mod); - } - - return mask; -} - -static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io) -{ - struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); - struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); - u32 mods; - - mods = rsnd_ssi_multi_secondaries_runtime(io) | - 1 << rsnd_mod_id(ssi_mod); - - if (ssi_parent_mod) - mods |= 1 << rsnd_mod_id(ssi_parent_mod); - - return mods; -} - -u32 rsnd_ssi_multi_secondaries_runtime(struct rsnd_dai_stream *io) -{ - if (rsnd_runtime_is_multi_ssi(io)) - return rsnd_ssi_multi_secondaries(io); - - return 0; -} - -static u32 rsnd_rdai_width_to_swl(struct rsnd_dai *rdai) -{ - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); - struct device *dev = rsnd_priv_to_dev(priv); - int width = rsnd_rdai_width_get(rdai); - - switch (width) { - case 32: return SWL_32; - case 24: return SWL_24; - case 16: return SWL_16; - } - - dev_err(dev, "unsupported slot width value: %d\n", width); - return 0; -} - -unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai, - int param1, int param2, int *idx) -{ - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); - static const int ssi_clk_mul_table[] = { - 1, 2, 4, 8, 16, 6, 12, - }; - int j, ret; - unsigned int main_rate; - int width = rsnd_rdai_width_get(rdai); - - for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) { - - /* - * It will set SSIWSR.CONT here, but SSICR.CKDV = 000 - * with it is not allowed. (SSIWSR.WS_MODE with - * SSICR.CKDV = 000 is not allowed either). - * Skip it. See SSICR.CKDV - */ - if (j == 0) - continue; - - main_rate = width * param1 * param2 * ssi_clk_mul_table[j]; - - ret = rsnd_adg_clk_query(priv, main_rate); - if (ret < 0) - continue; - - if (idx) - *idx = j; - - return main_rate; - } - - return 0; -} - -static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - int chan = rsnd_runtime_channel_for_ssi(io); - int idx, ret; - unsigned int main_rate; - unsigned int rate = rsnd_io_is_play(io) ? - rsnd_src_get_out_rate(priv, io) : - rsnd_src_get_in_rate(priv, io); - - if (!rsnd_rdai_is_clk_master(rdai)) - return 0; - - if (!rsnd_ssi_can_output_clk(mod)) - return 0; - - if (rsnd_ssi_is_multi_secondary(mod, io)) - return 0; - - if (rsnd_runtime_is_tdm_split(io)) - chan = rsnd_io_converted_chan(io); - - chan = rsnd_channel_normalization(chan); - - if (ssi->usrcnt > 0) { - if (ssi->rate != rate) { - dev_err(dev, "SSI parent/child should use same rate\n"); - return -EINVAL; - } - - if (ssi->chan != chan) { - dev_err(dev, "SSI parent/child should use same chan\n"); - return -EINVAL; - } - - return 0; - } - - ret = -EIO; - main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx); - if (!main_rate) - goto rate_err; - - ret = rsnd_adg_ssi_clk_try_start(mod, main_rate); - if (ret < 0) - goto rate_err; - - /* - * SSI clock will be output contiguously - * by below settings. - * This means, rsnd_ssi_master_clk_start() - * and rsnd_ssi_register_setup() are necessary - * for SSI parent - * - * SSICR : FORCE, SCKD, SWSD - * SSIWSR : CONT - */ - ssi->cr_clk = FORCE | rsnd_rdai_width_to_swl(rdai) | - SCKD | SWSD | CKDV(idx); - ssi->wsr = CONT; - ssi->rate = rate; - ssi->chan = chan; - - dev_dbg(dev, "%s outputs %d chan %u Hz\n", - rsnd_mod_name(mod), chan, rate); - - return 0; - -rate_err: - dev_err(dev, "unsupported clock rate\n"); - return ret; -} - -static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - - if (!rsnd_rdai_is_clk_master(rdai)) - return; - - if (!rsnd_ssi_can_output_clk(mod)) - return; - - if (ssi->usrcnt > 1) - return; - - ssi->cr_clk = 0; - ssi->rate = 0; - ssi->chan = 0; - - rsnd_adg_ssi_clk_stop(mod); -} - -static void rsnd_ssi_config_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); - struct device *dev = rsnd_priv_to_dev(priv); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - u32 cr_own = ssi->cr_own; - u32 cr_mode = ssi->cr_mode; - u32 wsr = ssi->wsr; - int width; - int is_tdm, is_tdm_split; - - is_tdm = rsnd_runtime_is_tdm(io); - is_tdm_split = rsnd_runtime_is_tdm_split(io); - - if (is_tdm) - dev_dbg(dev, "TDM mode\n"); - if (is_tdm_split) - dev_dbg(dev, "TDM Split mode\n"); - - cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai); - - if (rdai->bit_clk_inv) - cr_own |= SCKP; - if (rdai->frm_clk_inv && !is_tdm) - cr_own |= SWSP; - if (rdai->data_alignment) - cr_own |= SDTA; - if (rdai->sys_delay) - cr_own |= DEL; - - /* - * TDM Mode - * see - * rsnd_ssiu_init_gen2() - */ - if (is_tdm || is_tdm_split) { - wsr |= WS_MODE; - cr_own |= CHNL_8; - } - - /* - * We shouldn't exchange SWSP after running. - * This means, parent needs to care it. - */ - if (rsnd_ssi_is_parent(mod, io)) - goto init_end; - - if (rsnd_io_is_play(io)) - cr_own |= TRMD; - - cr_own &= ~DWL_MASK; - width = snd_pcm_format_width(runtime->format); - if (is_tdm_split) { - /* - * The SWL and DWL bits in SSICR should be fixed at 32-bit - * setting when TDM split mode. - * see datasheet - * Operation :: TDM Format Split Function (TDM Split Mode) - */ - width = 32; - } - - switch (width) { - case 8: - cr_own |= DWL_8; - break; - case 16: - cr_own |= DWL_16; - break; - case 24: - cr_own |= DWL_24; - break; - case 32: - cr_own |= DWL_32; - break; - } - - if (rsnd_ssi_is_dma_mode(mod)) { - cr_mode = UIEN | OIEN | /* over/under run */ - DMEN; /* DMA : enable DMA */ - } else { - cr_mode = DIEN; /* PIO : enable Data interrupt */ - } - -init_end: - ssi->cr_own = cr_own; - ssi->cr_mode = cr_mode; - ssi->wsr = wsr; -} - -static void rsnd_ssi_register_setup(struct rsnd_mod *mod) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - - rsnd_mod_write(mod, SSIWSR, ssi->wsr); - rsnd_mod_write(mod, SSICR, ssi->cr_own | - ssi->cr_clk | - ssi->cr_mode | - ssi->cr_en); -} - -/* - * SSI mod common functions - */ -static int rsnd_ssi_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - int ret; - - if (!rsnd_ssi_is_run_mods(mod, io)) - return 0; - - ret = rsnd_ssi_master_clk_start(mod, io); - if (ret < 0) - return ret; - - ssi->usrcnt++; - - ret = rsnd_mod_power_on(mod); - if (ret < 0) - return ret; - - rsnd_ssi_config_init(mod, io); - - rsnd_ssi_register_setup(mod); - - /* clear error status */ - rsnd_ssi_status_clear(mod); - - return 0; -} - -static int rsnd_ssi_quit(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct device *dev = rsnd_priv_to_dev(priv); - - if (!rsnd_ssi_is_run_mods(mod, io)) - return 0; - - if (!ssi->usrcnt) { - dev_err(dev, "%s usrcnt error\n", rsnd_mod_name(mod)); - return -EIO; - } - - rsnd_ssi_master_clk_stop(mod, io); - - rsnd_mod_power_off(mod); - - ssi->usrcnt--; - - if (!ssi->usrcnt) { - ssi->cr_own = 0; - ssi->cr_mode = 0; - ssi->wsr = 0; - } - - return 0; -} - -static int rsnd_ssi_hw_params(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - unsigned int fmt_width = snd_pcm_format_width(params_format(params)); - - if (fmt_width > rdai->chan_width) { - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct device *dev = rsnd_priv_to_dev(priv); - - dev_err(dev, "invalid combination of slot-width and format-data-width\n"); - return -EINVAL; - } - - return 0; -} - -static int rsnd_ssi_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - - if (!rsnd_ssi_is_run_mods(mod, io)) - return 0; - - /* - * EN will be set via SSIU :: SSI_CONTROL - * if Multi channel mode - */ - if (rsnd_ssi_multi_secondaries_runtime(io)) - return 0; - - /* - * EN is for data output. - * SSI parent EN is not needed. - */ - if (rsnd_ssi_is_parent(mod, io)) - return 0; - - ssi->cr_en = EN; - - rsnd_mod_write(mod, SSICR, ssi->cr_own | - ssi->cr_clk | - ssi->cr_mode | - ssi->cr_en); - - return 0; -} - -static int rsnd_ssi_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - u32 cr; - - if (!rsnd_ssi_is_run_mods(mod, io)) - return 0; - - if (rsnd_ssi_is_parent(mod, io)) - return 0; - - cr = ssi->cr_own | - ssi->cr_clk; - - /* - * disable all IRQ, - * Playback: Wait all data was sent - * Capture: It might not receave data. Do nothing - */ - if (rsnd_io_is_play(io)) { - rsnd_mod_write(mod, SSICR, cr | ssi->cr_en); - rsnd_ssi_status_check(mod, DIRQ); - } - - /* In multi-SSI mode, stop is performed by setting ssi0129 in - * SSI_CONTROL to 0 (in rsnd_ssio_stop_gen2). Do nothing here. - */ - if (rsnd_ssi_multi_secondaries_runtime(io)) - return 0; - - /* - * disable SSI, - * and, wait idle state - */ - rsnd_mod_write(mod, SSICR, cr); /* disabled all */ - rsnd_ssi_status_check(mod, IIRQ); - - ssi->cr_en = 0; - - return 0; -} - -static int rsnd_ssi_irq(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv, - int enable) -{ - u32 val = 0; - int is_tdm, is_tdm_split; - int id = rsnd_mod_id(mod); - - is_tdm = rsnd_runtime_is_tdm(io); - is_tdm_split = rsnd_runtime_is_tdm_split(io); - - if (rsnd_is_gen1(priv)) - return 0; - - if (rsnd_ssi_is_parent(mod, io)) - return 0; - - if (!rsnd_ssi_is_run_mods(mod, io)) - return 0; - - if (enable) - val = rsnd_ssi_is_dma_mode(mod) ? 0x0e000000 : 0x0f000000; - - if (is_tdm || is_tdm_split) { - switch (id) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 9: - val |= 0x0000ff00; - break; - } - } - - rsnd_mod_write(mod, SSI_INT_ENABLE, val); - - return 0; -} - -static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod, - struct rsnd_dai_stream *io); -static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - int is_dma = rsnd_ssi_is_dma_mode(mod); - u32 status; - bool elapsed = false; - bool stop = false; - - spin_lock(&priv->lock); - - /* ignore all cases if not working */ - if (!rsnd_io_is_working(io)) - goto rsnd_ssi_interrupt_out; - - status = rsnd_ssi_status_get(mod); - - /* PIO only */ - if (!is_dma && (status & DIRQ)) - elapsed = rsnd_ssi_pio_interrupt(mod, io); - - /* DMA only */ - if (is_dma && (status & (UIRQ | OIRQ))) { - rsnd_print_irq_status(dev, "%s err status : 0x%08x\n", - rsnd_mod_name(mod), status); - - stop = true; - } - - stop |= rsnd_ssiu_busif_err_status_clear(mod); - - rsnd_ssi_status_clear(mod); -rsnd_ssi_interrupt_out: - spin_unlock(&priv->lock); - - if (elapsed) - rsnd_dai_period_elapsed(io); - - if (stop) - snd_pcm_stop_xrun(io->substream); - -} - -static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) -{ - struct rsnd_mod *mod = data; - - rsnd_mod_interrupt(mod, __rsnd_ssi_interrupt); - - return IRQ_HANDLED; -} - -static u32 *rsnd_ssi_get_status(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - enum rsnd_mod_type type) -{ - /* - * SSIP (= SSI parent) needs to be special, otherwise, - * 2nd SSI might doesn't start. see also rsnd_mod_call() - * - * We can't include parent SSI status on SSI, because we don't know - * how many SSI requests parent SSI. Thus, it is localed on "io" now. - * ex) trouble case - * Playback: SSI0 - * Capture : SSI1 (needs SSI0) - * - * 1) start Capture -> SSI0/SSI1 are started. - * 2) start Playback -> SSI0 doesn't work, because it is already - * marked as "started" on 1) - * - * OTOH, using each mod's status is good for MUX case. - * It doesn't need to start in 2nd start - * ex) - * IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0 - * | - * IO-1: SRC1 -> CTU2 -+ - * - * 1) start IO-0 -> start SSI0 - * 2) start IO-1 -> SSI0 doesn't need to start, because it is - * already started on 1) - */ - if (type == RSND_MOD_SSIP) - return &io->parent_ssi_status; - - return rsnd_mod_get_status(mod, io, type); -} - -/* - * SSI PIO - */ -static void rsnd_ssi_parent_attach(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - - if (!__rsnd_ssi_is_pin_sharing(mod)) - return; - - if (!rsnd_rdai_is_clk_master(rdai)) - return; - - if (rsnd_ssi_is_multi_secondary(mod, io)) - return; - - switch (rsnd_mod_id(mod)) { - case 1: - case 2: - case 9: - rsnd_dai_connect(rsnd_ssi_mod_get(priv, 0), io, RSND_MOD_SSIP); - break; - case 4: - rsnd_dai_connect(rsnd_ssi_mod_get(priv, 3), io, RSND_MOD_SSIP); - break; - case 8: - rsnd_dai_connect(rsnd_ssi_mod_get(priv, 7), io, RSND_MOD_SSIP); - break; - } -} - -static int rsnd_ssi_pcm_new(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd) -{ - /* - * rsnd_rdai_is_clk_master() will be enabled after set_fmt, - * and, pcm_new will be called after it. - * This function reuse pcm_new at this point. - */ - rsnd_ssi_parent_attach(mod, io); - - return 0; -} - -static int rsnd_ssi_common_probe(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - int ret = 0; - - /* - * SSIP/SSIU/IRQ are not needed on - * SSI Multi secondaries - */ - if (rsnd_ssi_is_multi_secondary(mod, io)) - return 0; - - /* - * It can't judge ssi parent at this point - * see rsnd_ssi_pcm_new() - */ - - /* - * SSI might be called again as PIO fallback - * It is easy to manual handling for IRQ request/free - * - * OTOH, this function might be called many times if platform is - * using MIX. It needs xxx_attach() many times on xxx_probe(). - * Because of it, we can't control .probe/.remove calling count by - * mod->status. - * But it don't need to call request_irq() many times. - * Let's control it by RSND_SSI_PROBED flag. - */ - if (!rsnd_flags_has(ssi, RSND_SSI_PROBED)) { - ret = request_irq(ssi->irq, - rsnd_ssi_interrupt, - IRQF_SHARED, - dev_name(dev), mod); - - rsnd_flags_set(ssi, RSND_SSI_PROBED); - } - - return ret; -} - -static int rsnd_ssi_common_remove(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct rsnd_mod *pure_ssi_mod = rsnd_io_to_mod_ssi(io); - - /* Do nothing if non SSI (= SSI parent, multi SSI) mod */ - if (pure_ssi_mod != mod) - return 0; - - /* PIO will request IRQ again */ - if (rsnd_flags_has(ssi, RSND_SSI_PROBED)) { - free_irq(ssi->irq, mod); - - rsnd_flags_del(ssi, RSND_SSI_PROBED); - } - - return 0; -} - -/* - * SSI PIO functions - */ -static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - u32 *buf = (u32 *)(runtime->dma_area + ssi->byte_pos); - int shift = 0; - int byte_pos; - bool elapsed = false; - - if (snd_pcm_format_width(runtime->format) == 24) - shift = 8; - - /* - * 8/16/32 data can be assesse to TDR/RDR register - * directly as 32bit data - * see rsnd_ssi_init() - */ - if (rsnd_io_is_play(io)) - rsnd_mod_write(mod, SSITDR, (*buf) << shift); - else - *buf = (rsnd_mod_read(mod, SSIRDR) >> shift); - - byte_pos = ssi->byte_pos + sizeof(*buf); - - if (byte_pos >= ssi->next_period_byte) { - int period_pos = byte_pos / ssi->byte_per_period; - - if (period_pos >= runtime->periods) { - byte_pos = 0; - period_pos = 0; - } - - ssi->next_period_byte = (period_pos + 1) * ssi->byte_per_period; - - elapsed = true; - } - - WRITE_ONCE(ssi->byte_pos, byte_pos); - - return elapsed; -} - -static int rsnd_ssi_pio_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - - if (!rsnd_ssi_is_parent(mod, io)) { - ssi->byte_pos = 0; - ssi->byte_per_period = runtime->period_size * - runtime->channels * - samples_to_bytes(runtime, 1); - ssi->next_period_byte = ssi->byte_per_period; - } - - return rsnd_ssi_init(mod, io, priv); -} - -static int rsnd_ssi_pio_pointer(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - snd_pcm_uframes_t *pointer) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - - *pointer = bytes_to_frames(runtime, READ_ONCE(ssi->byte_pos)); - - return 0; -} - -static struct rsnd_mod_ops rsnd_ssi_pio_ops = { - .name = SSI_NAME, - .probe = rsnd_ssi_common_probe, - .remove = rsnd_ssi_common_remove, - .init = rsnd_ssi_pio_init, - .quit = rsnd_ssi_quit, - .start = rsnd_ssi_start, - .stop = rsnd_ssi_stop, - .irq = rsnd_ssi_irq, - .pointer = rsnd_ssi_pio_pointer, - .pcm_new = rsnd_ssi_pcm_new, - .hw_params = rsnd_ssi_hw_params, - .get_status = rsnd_ssi_get_status, -}; - -static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int ret; - - /* - * SSIP/SSIU/IRQ/DMA are not needed on - * SSI Multi secondaries - */ - if (rsnd_ssi_is_multi_secondary(mod, io)) - return 0; - - ret = rsnd_ssi_common_probe(mod, io, priv); - if (ret) - return ret; - - /* SSI probe might be called many times in MUX multi path */ - ret = rsnd_dma_attach(io, mod, &io->dma); - - return ret; -} - -static int rsnd_ssi_fallback(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct device *dev = rsnd_priv_to_dev(priv); - - /* - * fallback to PIO - * - * SSI .probe might be called again. - * see - * rsnd_rdai_continuance_probe() - */ - mod->ops = &rsnd_ssi_pio_ops; - - dev_info(dev, "%s fallback to PIO mode\n", rsnd_mod_name(mod)); - - return 0; -} - -static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - int is_play = rsnd_io_is_play(io); - char *name; - - /* - * It should use "rcar_sound,ssiu" on DT. - * But, we need to keep compatibility for old version. - * - * If it has "rcar_sound.ssiu", it will be used. - * If not, "rcar_sound.ssi" will be used. - * see - * rsnd_ssiu_dma_req() - * rsnd_dma_of_path() - */ - - if (rsnd_ssi_use_busif(io)) - name = is_play ? "rxu" : "txu"; - else - name = is_play ? "rx" : "tx"; - - return rsnd_dma_request_channel(rsnd_ssi_of_node(priv), - SSI_NAME, mod, name); -} - -#ifdef CONFIG_DEBUG_FS -static void rsnd_ssi_debug_info(struct seq_file *m, - struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - - seq_printf(m, "clock: %s\n", rsnd_rdai_is_clk_master(rdai) ? - "provider" : "consumer"); - seq_printf(m, "bit_clk_inv: %d\n", rdai->bit_clk_inv); - seq_printf(m, "frm_clk_inv: %d\n", rdai->frm_clk_inv); - seq_printf(m, "pin share: %d\n", __rsnd_ssi_is_pin_sharing(mod)); - seq_printf(m, "can out clk: %d\n", rsnd_ssi_can_output_clk(mod)); - seq_printf(m, "multi secondary: %d\n", rsnd_ssi_is_multi_secondary(mod, io)); - seq_printf(m, "tdm: %d, %d\n", rsnd_runtime_is_tdm(io), - rsnd_runtime_is_tdm_split(io)); - seq_printf(m, "chan: %d\n", ssi->chan); - seq_printf(m, "user: %d\n", ssi->usrcnt); - - rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SSI, - rsnd_mod_id(mod) * 0x40, 0x40); -} -#define DEBUG_INFO .debug_info = rsnd_ssi_debug_info -#else -#define DEBUG_INFO -#endif - -static struct rsnd_mod_ops rsnd_ssi_dma_ops = { - .name = SSI_NAME, - .dma_req = rsnd_ssi_dma_req, - .probe = rsnd_ssi_dma_probe, - .remove = rsnd_ssi_common_remove, - .init = rsnd_ssi_init, - .quit = rsnd_ssi_quit, - .start = rsnd_ssi_start, - .stop = rsnd_ssi_stop, - .irq = rsnd_ssi_irq, - .pcm_new = rsnd_ssi_pcm_new, - .fallback = rsnd_ssi_fallback, - .hw_params = rsnd_ssi_hw_params, - .get_status = rsnd_ssi_get_status, - DEBUG_INFO -}; - -int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) -{ - return mod->ops == &rsnd_ssi_dma_ops; -} - -/* - * ssi mod function - */ -static void rsnd_ssi_connect(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - static const enum rsnd_mod_type types[] = { - RSND_MOD_SSI, - RSND_MOD_SSIM1, - RSND_MOD_SSIM2, - RSND_MOD_SSIM3, - }; - enum rsnd_mod_type type; - int i; - - /* try SSI -> SSIM1 -> SSIM2 -> SSIM3 */ - for (i = 0; i < ARRAY_SIZE(types); i++) { - type = types[i]; - if (!rsnd_io_to_mod(io, type)) { - rsnd_dai_connect(mod, io, type); - rsnd_rdai_channels_set(rdai, (i + 1) * 2); - rsnd_rdai_ssi_lane_set(rdai, (i + 1)); - return; - } - } -} - -void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, - struct device_node *playback, - struct device_node *capture) -{ - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *node; - struct device_node *np; - int i; - - node = rsnd_ssi_of_node(priv); - if (!node) - return; - - i = 0; - for_each_child_of_node(node, np) { - struct rsnd_mod *mod; - - i = rsnd_node_fixed_index(dev, np, SSI_NAME, i); - if (i < 0) { - of_node_put(np); - break; - } - - mod = rsnd_ssi_mod_get(priv, i); - - if (np == playback) - rsnd_ssi_connect(mod, &rdai->playback); - if (np == capture) - rsnd_ssi_connect(mod, &rdai->capture); - i++; - } - - of_node_put(node); -} - -struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) -{ - if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) - id = 0; - - return rsnd_mod_get(rsnd_ssi_get(priv, id)); -} - -int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) -{ - if (!mod) - return 0; - - return !!(rsnd_flags_has(rsnd_mod_to_ssi(mod), RSND_SSI_CLK_PIN_SHARE)); -} - -int rsnd_ssi_probe(struct rsnd_priv *priv) -{ - struct device_node *node; - struct device_node *np; - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_mod_ops *ops; - struct clk *clk; - struct rsnd_ssi *ssi; - char name[RSND_SSI_NAME_SIZE]; - int i, nr, ret; - - node = rsnd_ssi_of_node(priv); - if (!node) - return -EINVAL; - - nr = rsnd_node_count(priv, node, SSI_NAME); - if (!nr) { - ret = -EINVAL; - goto rsnd_ssi_probe_done; - } - - ssi = devm_kcalloc(dev, nr, sizeof(*ssi), GFP_KERNEL); - if (!ssi) { - ret = -ENOMEM; - goto rsnd_ssi_probe_done; - } - - priv->ssi = ssi; - priv->ssi_nr = nr; - - i = 0; - for_each_child_of_node(node, np) { - if (!of_device_is_available(np)) - goto skip; - - i = rsnd_node_fixed_index(dev, np, SSI_NAME, i); - if (i < 0) { - ret = -EINVAL; - of_node_put(np); - goto rsnd_ssi_probe_done; - } - - ssi = rsnd_ssi_get(priv, i); - - snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d", - SSI_NAME, i); - - clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - of_node_put(np); - goto rsnd_ssi_probe_done; - } - - if (of_property_read_bool(np, "shared-pin")) - rsnd_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE); - - if (of_property_read_bool(np, "no-busif")) - rsnd_flags_set(ssi, RSND_SSI_NO_BUSIF); - - ssi->irq = irq_of_parse_and_map(np, 0); - if (!ssi->irq) { - ret = -EINVAL; - of_node_put(np); - goto rsnd_ssi_probe_done; - } - - if (of_property_read_bool(np, "pio-transfer")) - ops = &rsnd_ssi_pio_ops; - else - ops = &rsnd_ssi_dma_ops; - - ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk, - RSND_MOD_SSI, i); - if (ret) { - of_node_put(np); - goto rsnd_ssi_probe_done; - } -skip: - i++; - } - - ret = 0; - -rsnd_ssi_probe_done: - of_node_put(node); - - return ret; -} - -void rsnd_ssi_remove(struct rsnd_priv *priv) -{ - struct rsnd_ssi *ssi; - int i; - - for_each_rsnd_ssi(ssi, priv, i) { - rsnd_mod_quit(rsnd_mod_get(ssi)); - } -} diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c deleted file mode 100644 index 17bd8cc86dd0..000000000000 --- a/sound/soc/sh/rcar/ssiu.c +++ /dev/null @@ -1,609 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas R-Car SSIU support -// -// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> - -#include "rsnd.h" - -#define SSIU_NAME "ssiu" - -struct rsnd_ssiu { - struct rsnd_mod mod; - u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */ - unsigned int usrcnt; - int id; - int id_sub; -}; - -/* SSI_MODE */ -#define TDM_EXT (1 << 0) -#define TDM_SPLIT (1 << 8) - -#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr) -#define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod) -#define for_each_rsnd_ssiu(pos, priv, i) \ - for (i = 0; \ - (i < rsnd_ssiu_nr(priv)) && \ - ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \ - i++) - -/* - * SSI Gen2 Gen3 Gen4 - * 0 BUSIF0-3 BUSIF0-7 BUSIF0-7 - * 1 BUSIF0-3 BUSIF0-7 - * 2 BUSIF0-3 BUSIF0-7 - * 3 BUSIF0 BUSIF0-7 - * 4 BUSIF0 BUSIF0-7 - * 5 BUSIF0 BUSIF0 - * 6 BUSIF0 BUSIF0 - * 7 BUSIF0 BUSIF0 - * 8 BUSIF0 BUSIF0 - * 9 BUSIF0-3 BUSIF0-7 - * total 22 52 8 - */ -static const int gen2_id[] = { 0, 4, 8, 12, 13, 14, 15, 16, 17, 18 }; -static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 }; -static const int gen4_id[] = { 0 }; - -/* enable busif buffer over/under run interrupt. */ -#define rsnd_ssiu_busif_err_irq_enable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 1) -#define rsnd_ssiu_busif_err_irq_disable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 0) -static void rsnd_ssiu_busif_err_irq_ctrl(struct rsnd_mod *mod, int enable) -{ - int id = rsnd_mod_id(mod); - int shift, offset; - int i; - - switch (id) { - case 0: - case 1: - case 2: - case 3: - case 4: - shift = id; - offset = 0; - break; - case 9: - shift = 1; - offset = 1; - break; - default: - return; - } - - for (i = 0; i < 4; i++) { - enum rsnd_reg reg = SSI_SYS_INT_ENABLE((i * 2) + offset); - u32 val = 0xf << (shift * 4); - u32 sys_int_enable = rsnd_mod_read(mod, reg); - - if (enable) - sys_int_enable |= val; - else - sys_int_enable &= ~val; - rsnd_mod_write(mod, reg, sys_int_enable); - } -} - -bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod) -{ - bool error = false; - int id = rsnd_mod_id(mod); - int shift, offset; - int i; - - switch (id) { - case 0: - case 1: - case 2: - case 3: - case 4: - shift = id; - offset = 0; - break; - case 9: - shift = 1; - offset = 1; - break; - default: - goto out; - } - - for (i = 0; i < 4; i++) { - u32 reg = SSI_SYS_STATUS(i * 2) + offset; - u32 status = rsnd_mod_read(mod, reg); - u32 val = 0xf << (shift * 4); - - status &= val; - if (status) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - - rsnd_print_irq_status(dev, "%s err status : 0x%08x\n", - rsnd_mod_name(mod), status); - error = true; - } - rsnd_mod_write(mod, reg, val); - } -out: - return error; -} - -static u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - enum rsnd_mod_type type) -{ - struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); - int busif = rsnd_mod_id_sub(mod); - - return &ssiu->busif_status[busif]; -} - -static int rsnd_ssiu_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - u32 ssis = rsnd_ssi_multi_secondaries_runtime(io); - int use_busif = rsnd_ssi_use_busif(io); - int id = rsnd_mod_id(mod); - int is_clk_master = rsnd_rdai_is_clk_master(rdai); - u32 val1, val2; - - /* clear status */ - rsnd_ssiu_busif_err_status_clear(mod); - - /* Gen4 doesn't have SSI_MODE */ - if (rsnd_is_gen4(priv)) - goto ssi_mode_setting_end; - - /* - * SSI_MODE0 - */ - rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id); - - /* - * SSI_MODE1 / SSI_MODE2 - * - * FIXME - * sharing/multi with SSI0 are mainly supported - */ - val1 = rsnd_mod_read(mod, SSI_MODE1); - val2 = rsnd_mod_read(mod, SSI_MODE2); - if (rsnd_ssi_is_pin_sharing(io)) { - - ssis |= (1 << id); - - } else if (ssis) { - /* - * Multi SSI - * - * set synchronized bit here - */ - - /* SSI4 is synchronized with SSI3 */ - if (ssis & (1 << 4)) - val1 |= (1 << 20); - /* SSI012 are synchronized */ - if (ssis == 0x0006) - val1 |= (1 << 4); - /* SSI0129 are synchronized */ - if (ssis == 0x0206) - val2 |= (1 << 4); - } - - /* SSI1 is sharing pin with SSI0 */ - if (ssis & (1 << 1)) - val1 |= is_clk_master ? 0x2 : 0x1; - - /* SSI2 is sharing pin with SSI0 */ - if (ssis & (1 << 2)) - val1 |= is_clk_master ? 0x2 << 2 : - 0x1 << 2; - /* SSI4 is sharing pin with SSI3 */ - if (ssis & (1 << 4)) - val1 |= is_clk_master ? 0x2 << 16 : - 0x1 << 16; - /* SSI9 is sharing pin with SSI0 */ - if (ssis & (1 << 9)) - val2 |= is_clk_master ? 0x2 : 0x1; - - rsnd_mod_bset(mod, SSI_MODE1, 0x0013001f, val1); - rsnd_mod_bset(mod, SSI_MODE2, 0x00000017, val2); - -ssi_mode_setting_end: - /* - * Enable busif buffer over/under run interrupt. - * It will be handled from ssi.c - * see - * __rsnd_ssi_interrupt() - */ - rsnd_ssiu_busif_err_irq_enable(mod); - - return 0; -} - -static int rsnd_ssiu_quit(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - /* disable busif buffer over/under run interrupt. */ - rsnd_ssiu_busif_err_irq_disable(mod); - - return 0; -} - -static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = { - .name = SSIU_NAME, - .init = rsnd_ssiu_init, - .quit = rsnd_ssiu_quit, - .get_status = rsnd_ssiu_get_status, -}; - -static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); - u32 has_hdmi0 = rsnd_flags_has(io, RSND_STREAM_HDMI0); - u32 has_hdmi1 = rsnd_flags_has(io, RSND_STREAM_HDMI1); - int ret; - u32 mode = 0; - - ret = rsnd_ssiu_init(mod, io, priv); - if (ret < 0) - return ret; - - ssiu->usrcnt++; - - /* - * TDM Extend/Split Mode - * see - * rsnd_ssi_config_init() - */ - if (rsnd_runtime_is_tdm(io)) - mode = TDM_EXT; - else if (rsnd_runtime_is_tdm_split(io)) - mode = TDM_SPLIT; - - rsnd_mod_write(mod, SSI_MODE, mode); - - if (rsnd_ssi_use_busif(io)) { - int id = rsnd_mod_id(mod); - int busif = rsnd_mod_id_sub(mod); - enum rsnd_reg adinr_reg, mode_reg, dalign_reg; - - if ((id == 9) && (busif >= 4)) { - adinr_reg = SSI9_BUSIF_ADINR(busif); - mode_reg = SSI9_BUSIF_MODE(busif); - dalign_reg = SSI9_BUSIF_DALIGN(busif); - } else { - adinr_reg = SSI_BUSIF_ADINR(busif); - mode_reg = SSI_BUSIF_MODE(busif); - dalign_reg = SSI_BUSIF_DALIGN(busif); - } - - rsnd_mod_write(mod, adinr_reg, - rsnd_get_adinr_bit(mod, io) | - (rsnd_io_is_play(io) ? - rsnd_runtime_channel_after_ctu(io) : - rsnd_runtime_channel_original(io))); - rsnd_mod_write(mod, mode_reg, - rsnd_get_busif_shift(io, mod) | 1); - rsnd_mod_write(mod, dalign_reg, - rsnd_get_dalign(mod, io)); - } - - if (has_hdmi0 || has_hdmi1) { - enum rsnd_mod_type rsnd_ssi_array[] = { - RSND_MOD_SSIM1, - RSND_MOD_SSIM2, - RSND_MOD_SSIM3, - }; - struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); - struct rsnd_mod *pos; - u32 val; - int i; - - i = rsnd_mod_id(ssi_mod); - - /* output all same SSI as default */ - val = i << 16 | - i << 20 | - i << 24 | - i << 28 | - i; - - for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) { - int shift = (i * 4) + 20; - - val = (val & ~(0xF << shift)) | - rsnd_mod_id(pos) << shift; - } - - if (has_hdmi0) - rsnd_mod_write(mod, HDMI0_SEL, val); - if (has_hdmi1) - rsnd_mod_write(mod, HDMI1_SEL, val); - } - - return 0; -} - -static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int busif = rsnd_mod_id_sub(mod); - - if (!rsnd_ssi_use_busif(io)) - return 0; - - rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4)); - - if (rsnd_ssi_multi_secondaries_runtime(io)) - rsnd_mod_write(mod, SSI_CONTROL, 0x1); - - return 0; -} - -static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); - int busif = rsnd_mod_id_sub(mod); - - if (!rsnd_ssi_use_busif(io)) - return 0; - - rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0); - - if (--ssiu->usrcnt) - return 0; - - if (rsnd_ssi_multi_secondaries_runtime(io)) - rsnd_mod_write(mod, SSI_CONTROL, 0); - - return 0; -} - -static int rsnd_ssiu_id(struct rsnd_mod *mod) -{ - struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); - - /* see rsnd_ssiu_probe() */ - return ssiu->id; -} - -static int rsnd_ssiu_id_sub(struct rsnd_mod *mod) -{ - struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); - - /* see rsnd_ssiu_probe() */ - return ssiu->id_sub; -} - -static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - int is_play = rsnd_io_is_play(io); - char *name; - - /* - * It should use "rcar_sound,ssiu" on DT. - * But, we need to keep compatibility for old version. - * - * If it has "rcar_sound.ssiu", it will be used. - * If not, "rcar_sound.ssi" will be used. - * see - * rsnd_ssi_dma_req() - * rsnd_dma_of_path() - */ - - name = is_play ? "rx" : "tx"; - - return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv), - SSIU_NAME, mod, name); -} - -#ifdef CONFIG_DEBUG_FS -static void rsnd_ssiu_debug_info(struct seq_file *m, - struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SSIU, - rsnd_mod_id(mod) * 0x80, 0x80); -} -#define DEBUG_INFO .debug_info = rsnd_ssiu_debug_info -#else -#define DEBUG_INFO -#endif - -static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = { - .name = SSIU_NAME, - .dma_req = rsnd_ssiu_dma_req, - .init = rsnd_ssiu_init_gen2, - .quit = rsnd_ssiu_quit, - .start = rsnd_ssiu_start_gen2, - .stop = rsnd_ssiu_stop_gen2, - .get_status = rsnd_ssiu_get_status, - DEBUG_INFO -}; - -static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id) -{ - if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv))) - id = 0; - - return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id); -} - -static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv, - struct rsnd_dai_stream *io) -{ - struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); - struct rsnd_ssiu *ssiu; - int is_dma_mode; - int i; - - if (!ssi_mod) - return; - - is_dma_mode = rsnd_ssi_is_dma_mode(ssi_mod); - - /* select BUSIF0 */ - for_each_rsnd_ssiu(ssiu, priv, i) { - struct rsnd_mod *mod = rsnd_mod_get(ssiu); - - if (is_dma_mode && - (rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) && - (rsnd_mod_id_sub(mod) == 0)) { - rsnd_dai_connect(mod, io, mod->type); - return; - } - } -} - -void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai, - struct device_node *playback, - struct device_node *capture) -{ - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *node = rsnd_ssiu_of_node(priv); - struct rsnd_dai_stream *io_p = &rdai->playback; - struct rsnd_dai_stream *io_c = &rdai->capture; - - /* use rcar_sound,ssiu if exist */ - if (node) { - struct device_node *np; - int i = 0; - - for_each_child_of_node(node, np) { - struct rsnd_mod *mod; - - i = rsnd_node_fixed_index(dev, np, SSIU_NAME, i); - if (i < 0) { - of_node_put(np); - break; - } - - mod = rsnd_ssiu_mod_get(priv, i); - - if (np == playback) - rsnd_dai_connect(mod, io_p, mod->type); - if (np == capture) - rsnd_dai_connect(mod, io_c, mod->type); - i++; - } - - of_node_put(node); - } - - /* Keep DT compatibility */ - if (!rsnd_io_to_mod_ssiu(io_p)) - rsnd_parse_connect_ssiu_compatible(priv, io_p); - if (!rsnd_io_to_mod_ssiu(io_c)) - rsnd_parse_connect_ssiu_compatible(priv, io_c); -} - -int rsnd_ssiu_probe(struct rsnd_priv *priv) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *node; - struct rsnd_ssiu *ssiu; - struct rsnd_mod_ops *ops; - const int *list = NULL; - int i, nr; - - /* - * Keep DT compatibility. - * if it has "rcar_sound,ssiu", use it. - * if not, use "rcar_sound,ssi" - * see - * rsnd_ssiu_bufsif_to_id() - */ - node = rsnd_ssiu_of_node(priv); - if (node) - nr = rsnd_node_count(priv, node, SSIU_NAME); - else - nr = priv->ssi_nr; - - if (!nr) - return -EINVAL; - - ssiu = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL); - if (!ssiu) - return -ENOMEM; - - priv->ssiu = ssiu; - priv->ssiu_nr = nr; - - if (rsnd_is_gen1(priv)) - ops = &rsnd_ssiu_ops_gen1; - else - ops = &rsnd_ssiu_ops_gen2; - - /* Keep compatibility */ - nr = 0; - if ((node) && - (ops == &rsnd_ssiu_ops_gen2)) { - ops->id = rsnd_ssiu_id; - ops->id_sub = rsnd_ssiu_id_sub; - - if (rsnd_is_gen2(priv)) { - list = gen2_id; - nr = ARRAY_SIZE(gen2_id); - } else if (rsnd_is_gen3(priv)) { - list = gen3_id; - nr = ARRAY_SIZE(gen3_id); - } else if (rsnd_is_gen4(priv)) { - list = gen4_id; - nr = ARRAY_SIZE(gen4_id); - } else { - dev_err(dev, "unknown SSIU\n"); - return -ENODEV; - } - } - - for_each_rsnd_ssiu(ssiu, priv, i) { - int ret; - - if (node) { - int j; - - /* - * see - * rsnd_ssiu_get_id() - * rsnd_ssiu_get_id_sub() - */ - for (j = 0; j < nr; j++) { - if (list[j] > i) - break; - ssiu->id = j; - ssiu->id_sub = i - list[ssiu->id]; - } - } else { - ssiu->id = i; - } - - ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu), - ops, NULL, RSND_MOD_SSIU, i); - if (ret) - return ret; - } - - return 0; -} - -void rsnd_ssiu_remove(struct rsnd_priv *priv) -{ - struct rsnd_ssiu *ssiu; - int i; - - for_each_rsnd_ssiu(ssiu, priv, i) { - rsnd_mod_quit(rsnd_mod_get(ssiu)); - } -} |