@@ -48,7 +48,7 @@ enum rsnd_reg {
RSND_REG_SRC_IFSCR,
RSND_REG_SRC_IFSVR,
RSND_REG_SRC_SRCCR,
- RSND_REG_SRC_MNFSR,
+ RSND_REG_SRC_MNFSR, /* for Gen1 */
/* ADG */
RSND_REG_BRRA,
@@ -110,6 +110,9 @@ struct rsnd_scu {
*
*/
+/*
+ * Gen1/Gen2 common functions
+ */
static int rsnd_scu_ssi_mode_init(struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct rsnd_dai_stream *io)
@@ -151,11 +154,145 @@ static int rsnd_scu_ssi_mode_init(struct rsnd_mod *mod,
return 0;
}
-/* Gen1 only */
-static int rsnd_src_set_route_if_gen1(
- struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv,
+ struct rsnd_mod *ssi_mod,
+ struct snd_pcm_runtime *runtime)
+{
+ struct rsnd_scu *scu;
+ unsigned int rate;
+
+ /* this function is assuming SSI id = SCU id here */
+ scu = rsnd_mod_to_scu(rsnd_scu_mod_get(priv, rsnd_mod_id(ssi_mod)));
+
+ /*
+ * return convert rate if SRC is used,
+ * otherwise, return runtime->rate as usual
+ */
+ rate = rsnd_scu_convert_rate(scu);
+ if (!rate)
+ rate = runtime->rate;
+
+ return rate;
+}
+
+static int rsnd_scu_set_convert_rate(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
+ u32 convert_rate = rsnd_scu_convert_rate(scu);
+ u32 adinr = runtime->channels;
+ u32 fsrate = 0;
+
+ if (convert_rate)
+ fsrate = 0x0400000 / convert_rate * runtime->rate;
+
+ /* set/clear soft reset */
+ rsnd_mod_write(mod, SRC_SWRSR, 0);
+ rsnd_mod_write(mod, SRC_SWRSR, 1);
+
+ /*
+ * Initialize the operation of the SRC internal circuits
+ * see rsnd_scu_start()
+ */
+ rsnd_mod_write(mod, SRC_SRCIR, 1);
+
+ /* Set channel number and output bit length */
+ switch (runtime->sample_bits) {
+ case 16:
+ adinr |= OTBL_16;
+ break;
+ case 32:
+ adinr |= OTBL_24;
+ break;
+ default:
+ return -EIO;
+ }
+ rsnd_mod_write(mod, SRC_ADINR, adinr);
+
+ /* Enable the initial value of IFS */
+ if (fsrate) {
+ rsnd_mod_write(mod, SRC_IFSCR, 1);
+
+ /* Set initial value of IFS */
+ rsnd_mod_write(mod, SRC_IFSVR, fsrate);
+ }
+
+ /* use DMA transfer */
+ rsnd_mod_write(mod, SRC_BUSIF_MODE, 1);
+
+ return 0;
+}
+
+static int rsnd_scu_init(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
+ int ret;
+
+ clk_enable(scu->clk);
+
+ ret = rsnd_scu_ssi_mode_init(mod, rdai, io);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int rsnd_scu_quit(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
+
+ clk_disable(scu->clk);
+
+ return 0;
+}
+
+static int rsnd_scu_start(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
+
+ /*
+ * Cancel the initialization and operate the SRC function
+ * see rsnd_scu_set_convert_rate()
+ */
+ rsnd_mod_write(mod, SRC_SRCIR, 0);
+
+ if (rsnd_scu_convert_rate(scu))
+ rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
+
+ return 0;
+}
+
+
+static int rsnd_scu_stop(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
+
+ if (rsnd_scu_convert_rate(scu))
+ rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0);
+
+ return 0;
+}
+
+static struct rsnd_mod_ops rsnd_scu_non_ops = {
+ .name = "scu (non)",
+};
+
+/*
+ * Gen1 functions
+ */
+static int rsnd_src_set_route_gen1(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
{
struct scu_route_config {
u32 mask;
@@ -171,17 +308,10 @@ static int rsnd_src_set_route_if_gen1(
{ 0x3, 28, }, /* 7 */
{ 0x3, 30, }, /* 8 */
};
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
u32 mask;
u32 val;
int id;
- /*
- * Gen1 only
- */
- if (!rsnd_is_gen1(priv))
- return 0;
-
id = rsnd_mod_id(mod);
if (id < 0 || id >= ARRAY_SIZE(routes))
return -EIO;
@@ -257,104 +387,43 @@ static int rsnd_scu_set_convert_timing_gen1(struct rsnd_mod *mod,
return 0;
}
-unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv,
- struct rsnd_mod *ssi_mod,
- struct snd_pcm_runtime *runtime)
-{
- struct rsnd_scu *scu;
- unsigned int rate;
-
- /* this function is assuming SSI id = SCU id here */
- scu = rsnd_mod_to_scu(rsnd_scu_mod_get(priv, rsnd_mod_id(ssi_mod)));
-
- /*
- * return convert rate if SRC is used,
- * otherwise, return runtime->rate as usual
- */
- rate = rsnd_scu_convert_rate(scu);
- if (!rate)
- rate = runtime->rate;
-
- return rate;
-}
-
-static int rsnd_scu_set_convert_rate(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+static int rsnd_scu_set_convert_rate_gen1(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ 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 rsnd_scu *scu = rsnd_mod_to_scu(mod);
- u32 convert_rate = rsnd_scu_convert_rate(scu);
- u32 adinr = runtime->channels;
-
- /* set/clear soft reset */
- rsnd_mod_write(mod, SRC_SWRSR, 0);
- rsnd_mod_write(mod, SRC_SWRSR, 1);
-
- /* Initialize the operation of the SRC internal circuits */
- rsnd_mod_write(mod, SRC_SRCIR, 1);
-
- /* Set channel number and output bit length */
- switch (runtime->sample_bits) {
- case 16:
- adinr |= OTBL_16;
- break;
- case 32:
- adinr |= OTBL_24;
- break;
- default:
- return -EIO;
- }
- rsnd_mod_write(mod, SRC_ADINR, adinr);
-
- if (convert_rate) {
- u32 fsrate = 0x0400000 / convert_rate * runtime->rate;
-
- /* Enable the initial value of IFS */
- rsnd_mod_write(mod, SRC_IFSCR, 1);
-
- /* Set initial value of IFS */
- rsnd_mod_write(mod, SRC_IFSVR, fsrate);
-
- /* Select SRC mode (fixed value) */
- rsnd_mod_write(mod, SRC_SRCCR, 0x00010110);
+ int ret;
- /* Set the restriction value of the FS ratio (98%) */
- rsnd_mod_write(mod, SRC_MNFSR, fsrate / 100 * 98);
+ ret = rsnd_scu_set_convert_rate(mod, rdai, io);
+ if (ret < 0)
+ return ret;
- if (rsnd_is_gen1(priv)) {
- /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */
- }
- }
+ /* Select SRC mode (fixed value) */
+ rsnd_mod_write(mod, SRC_SRCCR, 0x00010110);
- /* Cancel the initialization and operate the SRC function */
- rsnd_mod_write(mod, SRC_SRCIR, 0);
+ /* Set the restriction value of the FS ratio (98%) */
+ rsnd_mod_write(mod, SRC_MNFSR,
+ rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98);
- /* use DMA transfer */
- rsnd_mod_write(mod, SRC_BUSIF_MODE, 1);
+ /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */
return 0;
}
-static int rsnd_scu_init(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+static int rsnd_scu_init_gen1(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
{
- struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
int ret;
- clk_enable(scu->clk);
-
- ret = rsnd_scu_ssi_mode_init(mod, rdai, io);
+ ret = rsnd_scu_init(mod, rdai, io);
if (ret < 0)
return ret;
- ret = rsnd_src_set_route_if_gen1(mod, rdai, io);
+ ret = rsnd_src_set_route_gen1(mod, rdai, io);
if (ret < 0)
return ret;
- ret = rsnd_scu_set_convert_rate(mod, rdai, io);
+ ret = rsnd_scu_set_convert_rate_gen1(mod, rdai, io);
if (ret < 0)
return ret;
@@ -365,62 +434,58 @@ static int rsnd_scu_init(struct rsnd_mod *mod,
return 0;
}
-static int rsnd_scu_quit(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+static int rsnd_scu_start_gen1(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
{
- struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
+ int id = rsnd_mod_id(mod);
- clk_disable(scu->clk);
+ rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id));
- return 0;
+ return rsnd_scu_start(mod, rdai, io);
}
-static int rsnd_scu_start(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+static int rsnd_scu_stop_gen1(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
{
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
int id = rsnd_mod_id(mod);
- if (rsnd_is_gen1(priv))
- rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id));
-
- if (rsnd_scu_convert_rate(scu))
- rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
+ rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0);
- return 0;
+ return rsnd_scu_stop(mod, rdai, io);
}
-static int rsnd_scu_stop(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
-{
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
- int id = rsnd_mod_id(mod);
+static struct rsnd_mod_ops rsnd_scu_gen1_ops = {
+ .name = "sru (gen1)",
+ .init = rsnd_scu_init_gen1,
+ .quit = rsnd_scu_quit,
+ .start = rsnd_scu_start_gen1,
+ .stop = rsnd_scu_stop_gen1,
+};
- if (rsnd_is_gen1(priv))
- rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0);
+static struct rsnd_mod_ops rsnd_scu_non_gen1_ops = {
+ .name = "non-sru (gen1)",
+ .init = rsnd_scu_ssi_mode_init,
+};
- if (rsnd_scu_convert_rate(scu))
- rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0);
+/*
+ * Gen2 functions
+ */
+static int rsnd_scu_start_non_gen2(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ /* enable PIO interrupt */
+ rsnd_mod_write(mod, INT_ENABLE, 0x0f000000);
return 0;
}
-static struct rsnd_mod_ops rsnd_scu_ops = {
- .name = "scu",
- .init = rsnd_scu_init,
- .quit = rsnd_scu_quit,
- .start = rsnd_scu_start,
- .stop = rsnd_scu_stop,
-};
-
-static struct rsnd_mod_ops rsnd_scu_non_ops = {
- .name = "scu (non)",
+static struct rsnd_mod_ops rsnd_scu_non_gen2_ops = {
+ .name = "non-scu (gen2)",
.init = rsnd_scu_ssi_mode_init,
+ .start = rsnd_scu_start_non_gen2,
};
struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id)
@@ -466,8 +531,15 @@ int rsnd_scu_probe(struct platform_device *pdev,
scu->clk = clk;
ops = &rsnd_scu_non_ops;
- if (rsnd_scu_hpbif_is_enable(scu))
- ops = &rsnd_scu_ops;
+ if (rsnd_scu_hpbif_is_enable(scu)) {
+ if (rsnd_is_gen1(priv))
+ ops = &rsnd_scu_gen1_ops;
+ } else {
+ if (rsnd_is_gen1(priv))
+ ops = &rsnd_scu_non_gen1_ops;
+ if (rsnd_is_gen2(priv))
+ ops = &rsnd_scu_non_gen2_ops;
+ }
rsnd_mod_init(priv, &scu->mod, ops, i);
@@ -363,16 +363,11 @@ static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct rsnd_dai_stream *io)
{
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
/* enable PIO IRQ */
ssi->cr_etc = UIEN | OIEN | DIEN;
- /* enable PIO interrupt if gen2 */
- if (rsnd_is_gen2(priv))
- rsnd_mod_write(&ssi->mod, INT_ENABLE, 0x0f000000);
-
rsnd_ssi_hw_start(ssi, rdai, io);
return 0;