diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 66203d107a11..d3b0dc145a56 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -507,7 +507,8 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, rbga = rbgx; adg->rbga_rate_for_441khz = rate / div; ckr |= brg_table[i] << 20; - if (req_441kHz_rate) + if (req_441kHz_rate && + !(adg_mode_flags(adg) & AUDIO_OUT_48)) parent_clk_name = __clk_get_name(clk); } } @@ -522,7 +523,8 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, rbgb = rbgx; adg->rbgb_rate_for_48khz = rate / div; ckr |= brg_table[i] << 16; - if (req_48kHz_rate) + if (req_48kHz_rate && + (adg_mode_flags(adg) & AUDIO_OUT_48)) parent_clk_name = __clk_get_name(clk); } } diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c index 7d92a24b7cfa..d879c010cf03 100644 --- a/sound/soc/sh/rcar/cmd.c +++ b/sound/soc/sh/rcar/cmd.c @@ -89,6 +89,7 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, dev_dbg(dev, "ctu/mix path = 0x%08x", 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); diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 1744015408c3..8c1f4e2e0c4f 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -343,6 +343,57 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) return 0x76543210; } +u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod) +{ + enum rsnd_mod_type playback_mods[] = { + RSND_MOD_SRC, + RSND_MOD_CMD, + RSND_MOD_SSIU, + }; + 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; + 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 + * + */ + switch (runtime->sample_bits) { + case 16: + return 0; + case 32: + break; + } + + 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 */ diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 63b6d3c28021..4b0980728e13 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -236,6 +236,7 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) 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), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index dbf4163427e8..323af41ecfcb 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -73,6 +73,7 @@ enum rsnd_reg { RSND_REG_SCU_SYS_INT_EN0, RSND_REG_SCU_SYS_INT_EN1, RSND_REG_CMD_CTRL, + RSND_REG_CMD_BUSIF_MODE, RSND_REG_CMD_BUSIF_DALIGN, RSND_REG_CMD_ROUTE_SLCT, RSND_REG_CMDOUT_TIMSEL, @@ -204,6 +205,7 @@ void rsnd_bset(struct rsnd_priv *priv, 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 diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 20b5b2ec625e..76a477a3ccb5 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -190,11 +190,13 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, 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 bsdsr, bsisr; + u32 i_busif, o_busif, tmp; uint ratio; if (!runtime) @@ -270,6 +272,11 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, break; } + /* 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 */ @@ -281,8 +288,9 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, rsnd_mod_write(mod, SRC_BSISR, bsisr); rsnd_mod_write(mod, SRC_SRCIR, 0); /* cancel initialize */ - rsnd_mod_write(mod, SRC_I_BUSIF_MODE, 1); - rsnd_mod_write(mod, SRC_O_BUSIF_MODE, 1); + 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); diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 135c5669f796..91e5c07911b4 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -302,7 +302,7 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, * always use 32bit system word. * see also rsnd_ssi_master_clk_enable() */ - cr_own = FORCE | SWL_32 | PDTA; + cr_own = FORCE | SWL_32; if (rdai->bit_clk_inv) cr_own |= SCKP; @@ -550,6 +550,13 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); u32 *buf = (u32 *)(runtime->dma_area + rsnd_dai_pointer_offset(io, 0)); + int shift = 0; + + switch (runtime->sample_bits) { + case 32: + shift = 8; + break; + } /* * 8/16/32 data can be assesse to TDR/RDR register @@ -557,9 +564,9 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, * see rsnd_ssi_init() */ if (rsnd_io_is_play(io)) - rsnd_mod_write(mod, SSITDR, *buf); + rsnd_mod_write(mod, SSITDR, (*buf) << shift); else - *buf = rsnd_mod_read(mod, SSIRDR); + *buf = (rsnd_mod_read(mod, SSIRDR) >> shift); elapsed = rsnd_dai_pointer_update(io, sizeof(*buf)); } @@ -709,6 +716,11 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); + + /* Do nothing for SSI parent mod */ + if (ssi_parent_mod == mod) + return 0; /* PIO will request IRQ again */ free_irq(ssi->irq, mod); diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 14fafdaf1395..512d238b79e2 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -144,7 +144,8 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, (rsnd_io_is_play(io) ? rsnd_runtime_channel_after_ctu(io) : rsnd_runtime_channel_original(io))); - rsnd_mod_write(mod, SSI_BUSIF_MODE, 1); + rsnd_mod_write(mod, SSI_BUSIF_MODE, + rsnd_get_busif_shift(io, mod) | 1); rsnd_mod_write(mod, SSI_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); }