diff options
Diffstat (limited to 'sound/soc/sh/rcar/src.c')
-rw-r--r-- | sound/soc/sh/rcar/src.c | 117 |
1 files changed, 65 insertions, 52 deletions
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index c61c17180..89a18e102 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -30,6 +30,7 @@ struct rsnd_src { #define RSND_SRC_NAME_SIZE 16 +#define rsnd_src_nr(priv) ((priv)->src_nr) #define rsnd_enable_sync_convert(src) ((src)->sen.val) #define rsnd_src_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") @@ -117,6 +118,20 @@ struct rsnd_src { /* * Gen1/Gen2 common functions */ +static void rsnd_src_soft_reset(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, SRC_SWRSR, 0); + rsnd_mod_write(mod, SRC_SWRSR, 1); +} + + +#define rsnd_src_initialize_lock(mod) __rsnd_src_initialize_lock(mod, 1) +#define rsnd_src_initialize_unlock(mod) __rsnd_src_initialize_lock(mod, 0) +static void __rsnd_src_initialize_lock(struct rsnd_mod *mod, u32 enable) +{ + rsnd_mod_write(mod, SRC_SRCIR, enable); +} + static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { @@ -133,7 +148,6 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, int use_busif) { struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); int ssi_id = rsnd_mod_id(ssi_mod); /* @@ -170,27 +184,14 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, * DMA settings for SSIU */ if (use_busif) { - u32 val = 0x76543210; - u32 mask = ~0; + u32 val = rsnd_get_dalign(ssi_mod, io); rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR, - rsnd_get_adinr(ssi_mod, io)); + rsnd_get_adinr_bit(ssi_mod, io)); rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1); rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1); - mask <<= runtime->channels * 4; - val = val & mask; - - switch (runtime->sample_bits) { - case 16: - val |= 0x67452301 & ~mask; - break; - case 32: - val |= 0x76543210 & ~mask; - break; - } - rsnd_mod_write(ssi_mod, BUSIF_DALIGN, val); - + rsnd_mod_write(ssi_mod, SSI_BUSIF_DALIGN, val); } return 0; @@ -215,10 +216,9 @@ int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod) return 0; /* enable SSI interrupt if Gen2 */ - if (rsnd_ssi_is_dma_mode(ssi_mod)) - rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0e000000); - else - rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0f000000); + rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, + rsnd_ssi_is_dma_mode(ssi_mod) ? + 0x0e000000 : 0x0f000000); return 0; } @@ -231,7 +231,7 @@ int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod) return 0; /* disable SSI interrupt if Gen2 */ - rsnd_mod_write(ssi_mod, INT_ENABLE, 0x00000000); + rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000); return 0; } @@ -294,12 +294,8 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod, 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); - /* Set channel number and output bit length */ - rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod, io)); + rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr_bit(mod, io)); /* Enable the initial value of IFS */ if (fsrate) { @@ -358,17 +354,15 @@ static int rsnd_src_init(struct rsnd_mod *mod, rsnd_mod_hw_start(mod); + rsnd_src_soft_reset(mod); + + rsnd_src_initialize_lock(mod); + src->err = 0; /* reset sync convert_rate */ src->sync.val = 0; - /* - * Initialize the operation of the SRC internal circuits - * see rsnd_src_start() - */ - rsnd_mod_write(mod, SRC_SRCIR, 1); - return 0; } @@ -395,11 +389,7 @@ static int rsnd_src_quit(struct rsnd_mod *mod, static int rsnd_src_start(struct rsnd_mod *mod) { - /* - * Cancel the initialization and operate the SRC function - * see rsnd_src_init() - */ - rsnd_mod_write(mod, SRC_SRCIR, 0); + rsnd_src_initialize_unlock(mod); return 0; } @@ -617,6 +607,14 @@ static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable) int_val = 0; } + /* + * WORKAROUND + * + * ignore over flow error when rsnd_enable_sync_convert() + */ + if (rsnd_enable_sync_convert(src)) + 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); @@ -632,11 +630,22 @@ static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod) static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod) { - u32 val = OUF_SRC(rsnd_mod_id(mod)); + struct rsnd_src *src = rsnd_mod_to_src(mod); + u32 val0, val1; bool ret = false; - if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val) || - (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val)) { + val0 = val1 = OUF_SRC(rsnd_mod_id(mod)); + + /* + * WORKAROUND + * + * ignore over flow error when rsnd_enable_sync_convert() + */ + if (rsnd_enable_sync_convert(src)) + val0 = val0 & 0xffff; + + if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val0) || + (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val1)) { struct rsnd_src *src = rsnd_mod_to_src(mod); src->err++; @@ -652,7 +661,20 @@ static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod) static int _rsnd_src_start_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { - u32 val = rsnd_io_to_mod_dvc(io) ? 0x01 : 0x11; + struct rsnd_src *src = rsnd_mod_to_src(mod); + u32 val; + + val = rsnd_get_dalign(mod, io); + + rsnd_mod_write(mod, SRC_BUSIF_DALIGN, val); + + /* + * WORKAROUND + * + * Enable SRC output if you want to use sync convert together with DVC + */ + val = (rsnd_io_to_mod_dvc(io) && !rsnd_enable_sync_convert(src)) ? + 0x01 : 0x11; rsnd_mod_write(mod, SRC_CTRL, val); @@ -922,13 +944,6 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod, return 0; /* - * We can't use SRC sync convert - * if it has DVC - */ - if (rsnd_io_to_mod_dvc(io)) - return 0; - - /* * enable sync convert */ ret = rsnd_kctrl_new_s(mod, io, rtd, @@ -1047,10 +1062,8 @@ int rsnd_src_probe(struct platform_device *pdev, return 0; src = devm_kzalloc(dev, sizeof(*src) * nr, GFP_KERNEL); - if (!src) { - dev_err(dev, "SRC allocate failed\n"); + if (!src) return -ENOMEM; - } priv->src_nr = nr; priv->src = src; |