From cd7bcc6000165f6215d15e2e32b58a646e5de5ec Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 19 Jun 2014 09:40:30 +0200 Subject: ASoC: rcar: Fix dma direction type dmaengine_prep_slave_single() expects a enum dma_transfer_direction and not a enum dma_data_direction. Since the integer representations of both DMA_TO_DEVICE and DMA_MEM_TO_DEV aswell as DMA_FROM_DEVICE and DMA_DEV_TO_MEM have the same value the code worked fine even though it was using the wrong type. Fixes the following warning from sparse: sound/soc/sh/rcar/core.c:227:49: warning: mixing different enum types sound/soc/sh/rcar/core.c:227:49: int enum dma_data_direction versus sound/soc/sh/rcar/core.c:227:49: int enum dma_transfer_direction Signed-off-by: Lars-Peter Clausen Acked-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 2 +- sound/soc/sh/rcar/rsnd.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 91880156e1ae..7bdda8fbde87 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -363,7 +363,7 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, if (ret < 0) goto rsnd_dma_init_err; - dma->dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + dma->dir = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; INIT_WORK(&dma->work, rsnd_dma_do_work); return 0; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 39d98af5ee05..067a89e9f25c 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -158,7 +158,7 @@ struct rsnd_dma { struct sh_dmae_slave slave; struct work_struct work; struct dma_chan *chan; - enum dma_data_direction dir; + enum dma_transfer_direction dir; int submit_loop; int offset; /* it cares A/B plane */ -- cgit v1.2.3 From ffb83e8cb14cace1b08ceb56695b580c808d8a41 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 22 Jun 2014 17:55:18 -0700 Subject: ASoC: fsi: use SNDRV_DMA_TYPE_DEV for sound buffer Current fsi driver is using SNDRV_DMA_TYPE_CONTINUOUS for snd_pcm_lib_preallocate_pages_for_all(). But, it came from original dma-sh7760.c, and no longer needed. This patch exchange its parameter, and removed original dma mapping and un-needed dma_sync_single_xxx() from driver. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 42 +++++------------------------------------- 1 file changed, 5 insertions(+), 37 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 710a079a7377..7a6b632c3db8 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -233,7 +233,6 @@ struct fsi_stream { */ struct dma_chan *chan; struct work_struct work; - dma_addr_t dma; int dma_id; int loop_cnt; int additional_pos; @@ -1279,11 +1278,6 @@ static irqreturn_t fsi_interrupt(int irq, void *data) */ static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io) { - struct snd_pcm_runtime *runtime = io->substream->runtime; - struct snd_soc_dai *dai = fsi_get_dai(io->substream); - enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ? - DMA_TO_DEVICE : DMA_FROM_DEVICE; - /* * 24bit data : 24bit bus / package in back * 16bit data : 16bit bus / stream mode @@ -1293,19 +1287,7 @@ static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io) io->loop_cnt = 2; /* push 1st, 2nd period first, then 3rd, 4th... */ io->additional_pos = 0; - io->dma = dma_map_single(dai->dev, runtime->dma_area, - snd_pcm_lib_buffer_bytes(io->substream), dir); - return 0; -} - -static int fsi_dma_quit(struct fsi_priv *fsi, struct fsi_stream *io) -{ - struct snd_soc_dai *dai = fsi_get_dai(io->substream); - enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ? - DMA_TO_DEVICE : DMA_FROM_DEVICE; - dma_unmap_single(dai->dev, io->dma, - snd_pcm_lib_buffer_bytes(io->substream), dir); return 0; } @@ -1317,7 +1299,8 @@ static dma_addr_t fsi_dma_get_area(struct fsi_stream *io, int additional) if (period >= runtime->periods) period = 0; - return io->dma + samples_to_bytes(runtime, period * io->period_samples); + return runtime->dma_addr + + samples_to_bytes(runtime, period * io->period_samples); } static void fsi_dma_complete(void *data) @@ -1325,12 +1308,6 @@ static void fsi_dma_complete(void *data) struct fsi_stream *io = (struct fsi_stream *)data; struct fsi_priv *fsi = fsi_stream_to_priv(io); struct snd_pcm_runtime *runtime = io->substream->runtime; - struct snd_soc_dai *dai = fsi_get_dai(io->substream); - enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ? - DMA_TO_DEVICE : DMA_FROM_DEVICE; - - dma_sync_single_for_cpu(dai->dev, fsi_dma_get_area(io, 0), - samples_to_bytes(runtime, io->period_samples), dir); io->buff_sample_pos += io->period_samples; io->period_pos++; @@ -1369,8 +1346,6 @@ static void fsi_dma_do_work(struct work_struct *work) for (i = 0; i < io->loop_cnt; i++) { buf = fsi_dma_get_area(io, io->additional_pos); - dma_sync_single_for_device(dai->dev, buf, len, dir); - desc = dmaengine_prep_slave_single(io->chan, buf, len, dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { @@ -1495,7 +1470,6 @@ static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io) static struct fsi_stream_handler fsi_dma_push_handler = { .init = fsi_dma_init, - .quit = fsi_dma_quit, .probe = fsi_dma_probe, .transfer = fsi_dma_transfer, .remove = fsi_dma_remove, @@ -1850,16 +1824,10 @@ static void fsi_pcm_free(struct snd_pcm *pcm) static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd) { - struct snd_pcm *pcm = rtd->pcm; - - /* - * dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel - * in MMAP mode (i.e. aplay -M) - */ return snd_pcm_lib_preallocate_pages_for_all( - pcm, - SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), + rtd->pcm, + SNDRV_DMA_TYPE_DEV, + rtd->card->snd_card->dev, PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); } -- cgit v1.2.3 From d403e24908836cf80531519530a9be84426e3a3f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 22 Jun 2014 17:55:41 -0700 Subject: ASoC: fsi: add fsi_pointer_update() for common pointer method fsi PIO/DMA handler are using each own pointer update method, but these can be share. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 57 +++++++++++++++++++++--------------------------------- 1 file changed, 22 insertions(+), 35 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 7a6b632c3db8..820a40833c04 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1041,6 +1041,26 @@ static int fsi_clk_set_rate_cpg(struct device *dev, return ret; } +static void fsi_pointer_update(struct fsi_stream *io, int size) +{ + io->buff_sample_pos += size; + + if (io->buff_sample_pos >= + io->period_samples * (io->period_pos + 1)) { + struct snd_pcm_substream *substream = io->substream; + struct snd_pcm_runtime *runtime = substream->runtime; + + io->period_pos++; + + if (io->period_pos >= runtime->periods) { + io->buff_sample_pos = 0; + io->period_pos = 0; + } + + snd_pcm_period_elapsed(substream); + } +} + /* * pio data transfer handler */ @@ -1107,31 +1127,11 @@ static int fsi_pio_transfer(struct fsi_priv *fsi, struct fsi_stream *io, void (*run32)(struct fsi_priv *fsi, u8 *buf, int samples), int samples) { - struct snd_pcm_runtime *runtime; - struct snd_pcm_substream *substream; u8 *buf; - int over_period; if (!fsi_stream_is_working(fsi, io)) return -EINVAL; - over_period = 0; - substream = io->substream; - runtime = substream->runtime; - - /* FSI FIFO has limit. - * So, this driver can not send periods data at a time - */ - if (io->buff_sample_pos >= - io->period_samples * (io->period_pos + 1)) { - - over_period = 1; - io->period_pos = (io->period_pos + 1) % runtime->periods; - - if (0 == io->period_pos) - io->buff_sample_pos = 0; - } - buf = fsi_pio_get_area(fsi, io); switch (io->sample_width) { @@ -1145,11 +1145,7 @@ static int fsi_pio_transfer(struct fsi_priv *fsi, struct fsi_stream *io, return -EINVAL; } - /* update buff_sample_pos */ - io->buff_sample_pos += samples; - - if (over_period) - snd_pcm_period_elapsed(substream); + fsi_pointer_update(io, samples); return 0; } @@ -1307,20 +1303,11 @@ static void fsi_dma_complete(void *data) { struct fsi_stream *io = (struct fsi_stream *)data; struct fsi_priv *fsi = fsi_stream_to_priv(io); - struct snd_pcm_runtime *runtime = io->substream->runtime; - io->buff_sample_pos += io->period_samples; - io->period_pos++; - - if (io->period_pos >= runtime->periods) { - io->period_pos = 0; - io->buff_sample_pos = 0; - } + fsi_pointer_update(io, io->period_samples); fsi_count_fifo_err(fsi); fsi_stream_transfer(io); - - snd_pcm_period_elapsed(io->substream); } static void fsi_dma_do_work(struct work_struct *work) -- cgit v1.2.3 From 8457e0e9e274cae4898f84dd5aaeb5d2098126c8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 22 Jun 2014 17:55:59 -0700 Subject: ASoC: fsi: use dmaengine_prep_dma_cyclic() for DMA transfer Current FSI driver is using DMAEngine directly, but, ASoC is requesting to use common DMA transfer method, like snd_dmaengine_pcm_trigger() or dmaengine_pcm_ops. It is difficult to switch at this point, since Renesas driver is also supporting PIO transfer. This patch uses dmaengine_prep_dma_cyclic() instead of dmaengine_prep_slave_single(). It is used in requested method, and is good first step to switch over. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 94 ++++++++++++++++-------------------------------------- 1 file changed, 27 insertions(+), 67 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 820a40833c04..a57eb96e57eb 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -232,10 +232,7 @@ struct fsi_stream { * these are for DMAEngine */ struct dma_chan *chan; - struct work_struct work; int dma_id; - int loop_cnt; - int additional_pos; }; struct fsi_clk { @@ -1281,24 +1278,9 @@ static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io) io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | BUSOP_SET(16, PACKAGE_16BITBUS_STREAM); - io->loop_cnt = 2; /* push 1st, 2nd period first, then 3rd, 4th... */ - io->additional_pos = 0; - return 0; } -static dma_addr_t fsi_dma_get_area(struct fsi_stream *io, int additional) -{ - struct snd_pcm_runtime *runtime = io->substream->runtime; - int period = io->period_pos + additional; - - if (period >= runtime->periods) - period = 0; - - return runtime->dma_addr + - samples_to_bytes(runtime, period * io->period_samples); -} - static void fsi_dma_complete(void *data) { struct fsi_stream *io = (struct fsi_stream *)data; @@ -1307,53 +1289,37 @@ static void fsi_dma_complete(void *data) fsi_pointer_update(io, io->period_samples); fsi_count_fifo_err(fsi); - fsi_stream_transfer(io); } -static void fsi_dma_do_work(struct work_struct *work) +static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) { - struct fsi_stream *io = container_of(work, struct fsi_stream, work); - struct fsi_priv *fsi = fsi_stream_to_priv(io); - struct snd_soc_dai *dai; + struct snd_soc_dai *dai = fsi_get_dai(io->substream); + struct snd_pcm_substream *substream = io->substream; struct dma_async_tx_descriptor *desc; - struct snd_pcm_runtime *runtime; - enum dma_data_direction dir; int is_play = fsi_stream_is_play(fsi, io); - int len, i; - dma_addr_t buf; - - if (!fsi_stream_is_working(fsi, io)) - return; - - dai = fsi_get_dai(io->substream); - runtime = io->substream->runtime; - dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; - len = samples_to_bytes(runtime, io->period_samples); - - for (i = 0; i < io->loop_cnt; i++) { - buf = fsi_dma_get_area(io, io->additional_pos); - - desc = dmaengine_prep_slave_single(io->chan, buf, len, dir, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n"); - return; - } - - desc->callback = fsi_dma_complete; - desc->callback_param = io; - - if (dmaengine_submit(desc) < 0) { - dev_err(dai->dev, "tx_submit() fail\n"); - return; - } + enum dma_data_direction dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + int ret = -EIO; + + desc = dmaengine_prep_dma_cyclic(io->chan, + substream->runtime->dma_addr, + snd_pcm_lib_buffer_bytes(substream), + snd_pcm_lib_period_bytes(substream), + dir, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_err(dai->dev, "dmaengine_prep_dma_cyclic() fail\n"); + goto fsi_dma_transfer_err; + } - dma_async_issue_pending(io->chan); + desc->callback = fsi_dma_complete; + desc->callback_param = io; - io->additional_pos = 1; + if (dmaengine_submit(desc) < 0) { + dev_err(dai->dev, "tx_submit() fail\n"); + goto fsi_dma_transfer_err; } - io->loop_cnt = 1; + dma_async_issue_pending(io->chan); /* * FIXME @@ -1370,13 +1336,11 @@ static void fsi_dma_do_work(struct work_struct *work) fsi_reg_write(fsi, DIFF_ST, 0); } } -} -static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) -{ - schedule_work(&io->work); + ret = 0; - return 0; +fsi_dma_transfer_err: + return ret; } static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, @@ -1437,15 +1401,11 @@ static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct dev return fsi_stream_probe(fsi, dev); } - INIT_WORK(&io->work, fsi_dma_do_work); - return 0; } static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io) { - cancel_work_sync(&io->work); - fsi_stream_stop(fsi, io); if (io->chan) @@ -1618,9 +1578,9 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, if (!ret) ret = fsi_hw_startup(fsi, io, dai->dev); if (!ret) - ret = fsi_stream_transfer(io); + ret = fsi_stream_start(fsi, io); if (!ret) - fsi_stream_start(fsi, io); + ret = fsi_stream_transfer(io); break; case SNDRV_PCM_TRIGGER_STOP: if (!ret) -- cgit v1.2.3 From d9288d0ba12de1b5efb830b9128e4cc6877318fc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 22 Jun 2014 17:56:23 -0700 Subject: ASoC: rsnd: SSI + DMA can select BUSIF Sound data needs to be sent to R-Car sound SSI when playback. But, there are 2 interfaces for it. 1st is SSITDR/SSIRDR which are mapped on SSI. 2nd is SSIn_BUSIF which are mapped on SSIU. 2nd SSIn_BUSIF is used when DMA transfer, and it is always used if sound data came from via SRC. But, we can use it when SSI+DMA case too. (Current driver is assuming 1st SSITDR/SSIRDR for it) 2nd SSIn_BUSIF can be used as FIFO. This is very helpful/useful for SSI+DMA. But DMA address / DMA ID are not same between 1st/2nd cases. This patch care about these settings. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 22 +++++++++++------ sound/soc/sh/rcar/gen.c | 64 +++++++++++++++++++++++++++++++----------------- sound/soc/sh/rcar/rsnd.h | 10 ++++++-- sound/soc/sh/rcar/src.c | 37 ++++++++++++++++++++-------- sound/soc/sh/rcar/ssi.c | 33 +++++++++++++++++++++++-- 5 files changed, 121 insertions(+), 45 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 7f68b33dcbbb..8c3707a68603 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -138,6 +138,17 @@ char *rsnd_mod_name(struct rsnd_mod *mod) return mod->ops->name; } +char *rsnd_mod_dma_name(struct rsnd_mod *mod) +{ + if (!mod || !mod->ops) + return "unknown"; + + if (!mod->ops->dma_name) + return mod->ops->name; + + return mod->ops->dma_name(mod); +} + void rsnd_mod_init(struct rsnd_priv *priv, struct rsnd_mod *mod, struct rsnd_mod_ops *ops, @@ -261,7 +272,7 @@ static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod) { if (mod) return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d", - rsnd_mod_name(mod), rsnd_mod_id(mod)); + rsnd_mod_dma_name(mod), rsnd_mod_id(mod)); else return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem"); @@ -343,11 +354,8 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - if (dev->of_node) - rsnd_dma_of_name(dma, is_play, dma_name); - else - snprintf(dma_name, DMA_NAME_SIZE, - is_play ? "tx" : "rx"); + rsnd_dma_of_name(dma, is_play, dma_name); + rsnd_gen_dma_addr(priv, dma, &cfg, is_play, id); dev_dbg(dev, "dma name : %s\n", dma_name); @@ -359,8 +367,6 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, return -EIO; } - rsnd_gen_dma_addr(priv, dma, &cfg, is_play, id); - ret = dmaengine_slave_config(dma->chan, &cfg); if (ret < 0) goto rsnd_dma_init_err; diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 0280a11c0899..46677af6c748 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -165,15 +165,19 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv, * * ex) R-Car H2 case * mod / DMAC in / DMAC out / DMAC PP in / DMAC pp out - * SSI : 0xec541000 / 0xec241008 / 0xec24100c / 0xec400000 / 0xec400000 + * 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_SSI_I_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) -#define RDMA_SSI_O_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) +#define RDMA_SSIU_I_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i)) +#define RDMA_SSIU_O_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i)) + +#define RDMA_SSIU_I_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) +#define RDMA_SSIU_O_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) #define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i)) #define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i)) @@ -204,26 +208,36 @@ static void rsnd_gen2_dma_addr(struct rsnd_priv *priv, struct dma_addr { dma_addr_t src_addr; dma_addr_t dst_addr; - } dma_addrs[2][2][3] = { - { /* SRC */ - /* Capture */ - {{ 0, 0 }, - { RDMA_SRC_O_N(src, id), 0 }, - { RDMA_CMD_O_N(src, id), 0 }}, - /* Playback */ - {{ 0, 0, }, - { 0, RDMA_SRC_I_N(src, id) }, - { 0, RDMA_SRC_I_N(src, id) }} - }, { /* SSI */ - /* Capture */ - {{ RDMA_SSI_O_N(ssi, id), 0 }, - { RDMA_SSI_O_P(ssi, id), RDMA_SRC_I_P(src, id) }, - { RDMA_SSI_O_P(ssi, id), RDMA_SRC_I_P(src, id) }}, - /* Playback */ - {{ 0, RDMA_SSI_I_N(ssi, id) }, - { RDMA_SRC_O_P(src, id), RDMA_SSI_I_P(ssi, id) }, - { RDMA_CMD_O_P(src, id), RDMA_SSI_I_P(ssi, id) }} - } + } dma_addrs[3][2][3] = { + /* SRC */ + {{{ 0, 0 }, + /* Capture */ + { RDMA_SRC_O_N(src, id), 0 }, + { RDMA_CMD_O_N(src, id), 0 } }, + /* Playback */ + {{ 0, 0, }, + { 0, RDMA_SRC_I_N(src, id) }, + { 0, RDMA_SRC_I_N(src, id) } } + }, + /* SSI */ + /* Capture */ + {{{ RDMA_SSI_O_N(ssi, id), 0 }, + { 0, 0 }, + { 0, 0 } }, + /* Playback */ + {{ 0, RDMA_SSI_I_N(ssi, id) }, + { 0, 0 }, + { 0, 0 } } + }, + /* SSIU */ + /* Capture */ + {{{ RDMA_SSIU_O_N(ssi, id), 0 }, + { RDMA_SSIU_O_P(ssi, id), RDMA_SRC_I_P(src, id) }, + { RDMA_SSIU_O_P(ssi, id), RDMA_SRC_I_P(src, id) } }, + /* Playback */ + {{ 0, RDMA_SSIU_I_N(ssi, id) }, + { RDMA_SRC_O_P(src, id), RDMA_SSIU_I_P(ssi, id) }, + { RDMA_CMD_O_P(src, id), RDMA_SSIU_I_P(ssi, id) } } }, }; /* it shouldn't happen */ @@ -232,6 +246,10 @@ static void rsnd_gen2_dma_addr(struct rsnd_priv *priv, return; } + /* use SSIU or SSI ? */ + if (is_ssi && (0 == strcmp(rsnd_mod_dma_name(mod), "ssiu"))) + is_ssi++; + cfg->src_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].src_addr; cfg->dst_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].dst_addr; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 067a89e9f25c..a1466c1570bc 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -185,6 +185,7 @@ enum rsnd_mod_type { struct rsnd_mod_ops { char *name; + char* (*dma_name)(struct rsnd_mod *mod); int (*probe)(struct rsnd_mod *mod, struct rsnd_dai *rdai); int (*remove)(struct rsnd_mod *mod, @@ -224,6 +225,7 @@ void rsnd_mod_init(struct rsnd_priv *priv, enum rsnd_mod_type type, int id); char *rsnd_mod_name(struct rsnd_mod *mod); +char *rsnd_mod_dma_name(struct rsnd_mod *mod); /* * R-Car sound DAI @@ -391,8 +393,12 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, struct rsnd_dai_stream *io, struct snd_pcm_runtime *runtime); -int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, - struct rsnd_dai *rdai); +int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, + struct rsnd_dai *rdai, + int use_busif); +int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, + struct rsnd_dai *rdai, + int use_busif); int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod, struct rsnd_dai *rdai); diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 200eda019bc7..4d39505c21cf 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -106,18 +106,17 @@ struct rsnd_src { /* * Gen1/Gen2 common functions */ -int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, - struct rsnd_dai *rdai) +int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, + struct rsnd_dai *rdai, + int use_busif) { - struct rsnd_dai_stream *io = rsnd_mod_to_io(ssi_mod); - struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); int ssi_id = rsnd_mod_id(ssi_mod); /* * SSI_MODE0 */ rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id), - src_mod ? 0 : (1 << ssi_id)); + !use_busif << ssi_id); /* * SSI_MODE1 @@ -143,6 +142,29 @@ int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, 0x2 << shift : 0x1 << shift); } + /* + * DMA settings for SSIU + */ + if (use_busif) { + rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR, + rsnd_get_adinr(ssi_mod)); + rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1); + rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1); + } + + return 0; +} + +int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, + struct rsnd_dai *rdai, + int use_busif) +{ + /* + * DMA settings for SSIU + */ + if (use_busif) + rsnd_mod_write(ssi_mod, SSI_CTRL, 0); + return 0; } @@ -467,9 +489,6 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, if (ret < 0) return ret; - rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_get_adinr(mod)); - rsnd_mod_write(mod, SSI_BUSIF_MODE, 1); - rsnd_mod_write(mod, SRC_SRCCR, 0x00011110); rsnd_mod_write(mod, SRC_BSDSR, 0x01800000); @@ -554,7 +573,6 @@ static int rsnd_src_start_gen2(struct rsnd_mod *mod, rsnd_dma_start(rsnd_mod_to_dma(&src->mod)); - rsnd_mod_write(mod, SSI_CTRL, 0x1); rsnd_mod_write(mod, SRC_CTRL, val); return rsnd_src_start(mod, rdai); @@ -565,7 +583,6 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod, { struct rsnd_src *src = rsnd_mod_to_src(mod); - rsnd_mod_write(mod, SSI_CTRL, 0); rsnd_mod_write(mod, SRC_CTRL, 0); rsnd_dma_stop(rsnd_mod_to_dma(&src->mod)); diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 2df723df5d19..34e84009162b 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -90,6 +90,20 @@ struct rsnd_ssi { #define rsnd_ssi_mode_flags(p) ((p)->info->flags) #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) +static int rsnd_ssi_use_busif(struct rsnd_mod *mod) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + int use_busif = 0; + + if (!(rsnd_ssi_mode_flags(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_check(struct rsnd_mod *mod, u32 bit) { @@ -289,8 +303,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, ssi->cr_own = cr; ssi->err = -1; /* ignore 1st error */ - rsnd_src_ssi_mode_init(mod, rdai); - return 0; } @@ -389,6 +401,8 @@ static int rsnd_ssi_pio_start(struct rsnd_mod *mod, /* enable PIO IRQ */ ssi->cr_etc = UIEN | OIEN | DIEN; + rsnd_src_ssiu_start(mod, rdai, 0); + rsnd_src_enable_ssi_irq(mod, rdai); rsnd_ssi_hw_start(ssi, rdai, io); @@ -405,6 +419,8 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod, rsnd_ssi_hw_stop(ssi, rdai); + rsnd_src_ssiu_stop(mod, rdai, 0); + return 0; } @@ -457,6 +473,8 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod, /* enable DMA transfer */ ssi->cr_etc = DMEN; + rsnd_src_ssiu_start(mod, rdai, rsnd_ssi_use_busif(mod)); + rsnd_dma_start(dma); rsnd_ssi_hw_start(ssi, ssi->rdai, io); @@ -482,11 +500,19 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, rsnd_dma_stop(dma); + rsnd_src_ssiu_stop(mod, rdai, 1); + return 0; } +static char *rsnd_ssi_dma_name(struct rsnd_mod *mod) +{ + return rsnd_ssi_use_busif(mod) ? "ssiu" : SSI_NAME; +} + static struct rsnd_mod_ops rsnd_ssi_dma_ops = { .name = SSI_NAME, + .dma_name = rsnd_ssi_dma_name, .probe = rsnd_ssi_dma_probe, .remove = rsnd_ssi_dma_remove, .init = rsnd_ssi_init, @@ -595,6 +621,9 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev, */ ssi_info->dma_id = of_get_property(np, "pio-transfer", NULL) ? 0 : 1; + + if (of_get_property(np, "no-busif", NULL)) + ssi_info->flags |= RSND_SSI_NO_BUSIF; } rsnd_of_parse_ssi_end: -- cgit v1.2.3 From ccd01559ead29b59918458e9b412ff18b88fc6cf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 22 Jun 2014 17:56:41 -0700 Subject: ASoC: rsnd: use dmaengine_prep_dma_cyclic() instead of original method Current R-Car sound driver is using DMAEngine directly, but, ASoC is requesting to use common DMA transfer method, like snd_dmaengine_pcm_trigger() or dmaengine_pcm_ops. It is difficult to switch at this point, since Renesas driver is also supporting PIO transfer. This patch uses dmaengine_prep_dma_cyclic() instead of dmaengine_prep_slave_single(). It is used in requested method, and is good first step to switch over. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 76 ++++++++++++------------------------------------ sound/soc/sh/rcar/rsnd.h | 4 --- 2 files changed, 18 insertions(+), 62 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 8c3707a68603..5149fe2dae9f 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -164,26 +164,8 @@ void rsnd_mod_init(struct rsnd_priv *priv, /* * rsnd_dma functions */ -static void __rsnd_dma_start(struct rsnd_dma *dma); -static void rsnd_dma_continue(struct rsnd_dma *dma) -{ - /* push next A or B plane */ - dma->submit_loop = 1; - schedule_work(&dma->work); -} - -void rsnd_dma_start(struct rsnd_dma *dma) -{ - /* push both A and B plane*/ - dma->offset = 0; - dma->submit_loop = 2; - __rsnd_dma_start(dma); -} - void rsnd_dma_stop(struct rsnd_dma *dma) { - dma->submit_loop = 0; - cancel_work_sync(&dma->work); dmaengine_terminate_all(dma->chan); } @@ -191,11 +173,7 @@ static void rsnd_dma_complete(void *data) { struct rsnd_dma *dma = (struct rsnd_dma *)data; struct rsnd_mod *mod = rsnd_dma_to_mod(dma); - struct rsnd_priv *priv = rsnd_mod_to_priv(rsnd_dma_to_mod(dma)); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); - unsigned long flags; - - rsnd_lock(priv, flags); /* * Renesas sound Gen1 needs 1 DMAC, @@ -208,57 +186,40 @@ static void rsnd_dma_complete(void *data) * rsnd_dai_pointer_update() will be called twice, * ant it will breaks io->byte_pos */ - if (dma->submit_loop) - rsnd_dma_continue(dma); - - rsnd_unlock(priv, flags); rsnd_dai_pointer_update(io, io->byte_per_period); } -static void __rsnd_dma_start(struct rsnd_dma *dma) +void rsnd_dma_start(struct rsnd_dma *dma) { struct rsnd_mod *mod = rsnd_dma_to_mod(dma); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct snd_pcm_substream *substream = io->substream; struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; - dma_addr_t buf; - size_t len = io->byte_per_period; - int i; - - for (i = 0; i < dma->submit_loop; i++) { - buf = runtime->dma_addr + - rsnd_dai_pointer_offset(io, dma->offset + len); - dma->offset = len; + desc = dmaengine_prep_dma_cyclic(dma->chan, + substream->runtime->dma_addr, + snd_pcm_lib_buffer_bytes(substream), + snd_pcm_lib_period_bytes(substream), + dma->dir, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - desc = dmaengine_prep_slave_single( - dma->chan, buf, len, dma->dir, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - dev_err(dev, "dmaengine_prep_slave_sg() fail\n"); - return; - } - - desc->callback = rsnd_dma_complete; - desc->callback_param = dma; + if (!desc) { + dev_err(dev, "dmaengine_prep_slave_sg() fail\n"); + return; + } - if (dmaengine_submit(desc) < 0) { - dev_err(dev, "dmaengine_submit() fail\n"); - return; - } + desc->callback = rsnd_dma_complete; + desc->callback_param = dma; - dma_async_issue_pending(dma->chan); + if (dmaengine_submit(desc) < 0) { + dev_err(dev, "dmaengine_submit() fail\n"); + return; } -} - -static void rsnd_dma_do_work(struct work_struct *work) -{ - struct rsnd_dma *dma = container_of(work, struct rsnd_dma, work); - __rsnd_dma_start(dma); + dma_async_issue_pending(dma->chan); } int rsnd_dma_available(struct rsnd_dma *dma) @@ -372,7 +333,6 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, goto rsnd_dma_init_err; dma->dir = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; - INIT_WORK(&dma->work, rsnd_dma_do_work); return 0; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index a1466c1570bc..60b5e9260600 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -156,12 +156,8 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod); */ struct rsnd_dma { struct sh_dmae_slave slave; - struct work_struct work; struct dma_chan *chan; enum dma_transfer_direction dir; - - int submit_loop; - int offset; /* it cares A/B plane */ }; void rsnd_dma_start(struct rsnd_dma *dma); -- cgit v1.2.3 From 65f459923b7926f6a7f156970d83360bd80cb169 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 22 Jun 2014 17:57:04 -0700 Subject: ASoC: rsnd: enable DVC when capture Current DVC can be enabled only when playback, but, this came from misunderstanding. It is not correct. DVC <-> DMA relationship is... Playback: MEM -> DMAC -> SRC -> DVC -> DMACp -> SSI Capture: SSI -> DMACp -> SRC -> DVC -> DMAC -> MEM DVC can be used for both Playback/Capture Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dvc.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index ed0007006899..deef310c75dc 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -191,24 +191,20 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, struct snd_soc_pcm_runtime *rtd) { struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); struct snd_card *card = rtd->card->snd_card; struct snd_kcontrol *kctrl; static struct snd_kcontrol_new knew = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Playback Volume", .info = rsnd_dvc_volume_info, .get = rsnd_dvc_volume_get, .put = rsnd_dvc_volume_put, }; int ret; - if (!rsnd_dai_is_play(rdai, io)) { - dev_err(dev, "DVC%d is connected to Capture DAI\n", - rsnd_mod_id(mod)); - return -EINVAL; - } + if (rsnd_dai_is_play(rdai, io)) + knew.name = "Playback Volume"; + else + knew.name = "Capture Volume"; kctrl = snd_ctl_new1(&knew, mod); if (!kctrl) -- cgit v1.2.3 From 37523034851d6a4b1dc951e24bf2f11bc28fe58d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 22 Jun 2014 17:58:26 -0700 Subject: ASoC: rsnd: DMA cleanup for flexible SSI/SRC selection Current R-Car sound SSI/SRC/DVC selection has feature limit. (It is assuming that SSI/SRC are using same index number) So that enabling SSI/SRC flexible selection, this patch modifies DMA settings. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 45 ++++++++++++++++++++---------- sound/soc/sh/rcar/gen.c | 71 +++++++++++++++++++++--------------------------- sound/soc/sh/rcar/rsnd.h | 7 ++--- 3 files changed, 64 insertions(+), 59 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 5149fe2dae9f..4435a31ecdad 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -239,8 +239,21 @@ static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod) } -static void rsnd_dma_of_name(struct rsnd_dma *dma, - int is_play, char *dma_name) +static void rsnd_dma_of_name(struct rsnd_mod *mod_from, + struct rsnd_mod *mod_to, + char *dma_name) +{ + int index = 0; + + index = _rsnd_dma_of_name(dma_name + index, mod_from); + *(dma_name + index++) = '_'; + index = _rsnd_dma_of_name(dma_name + index, mod_to); +} + +static void rsnd_dma_of_path(struct rsnd_dma *dma, + int is_play, + struct rsnd_mod **mod_from, + struct rsnd_mod **mod_to) { struct rsnd_mod *this = rsnd_dma_to_mod(dma); struct rsnd_dai_stream *io = rsnd_mod_to_io(this); @@ -248,7 +261,6 @@ static void rsnd_dma_of_name(struct rsnd_dma *dma, struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); struct rsnd_mod *mod[MOD_MAX]; - struct rsnd_mod *src_mod, *dst_mod; int i, index; @@ -285,17 +297,12 @@ static void rsnd_dma_of_name(struct rsnd_dma *dma, } if (is_play) { - src_mod = mod[index - 1]; - dst_mod = mod[index]; + *mod_from = mod[index - 1]; + *mod_to = mod[index]; } else { - src_mod = mod[index]; - dst_mod = mod[index - 1]; + *mod_from = mod[index]; + *mod_to = mod[index - 1]; } - - index = 0; - index = _rsnd_dma_of_name(dma_name + index, src_mod); - *(dma_name + index++) = '_'; - index = _rsnd_dma_of_name(dma_name + index, dst_mod); } int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, @@ -303,6 +310,8 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, { struct device *dev = rsnd_priv_to_dev(priv); struct dma_slave_config cfg; + struct rsnd_mod *mod_from; + struct rsnd_mod *mod_to; char dma_name[DMA_NAME_SIZE]; dma_cap_mask_t mask; int ret; @@ -315,10 +324,16 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - rsnd_dma_of_name(dma, is_play, dma_name); - rsnd_gen_dma_addr(priv, dma, &cfg, is_play, id); + rsnd_dma_of_path(dma, is_play, &mod_from, &mod_to); + rsnd_dma_of_name(mod_from, mod_to, dma_name); + + cfg.slave_id = id; + cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; + cfg.src_addr = rsnd_gen_dma_addr(priv, mod_from, is_play, 1); + cfg.dst_addr = rsnd_gen_dma_addr(priv, mod_to, is_play, 0); - dev_dbg(dev, "dma name : %s\n", dma_name); + dev_dbg(dev, "dma : %s %pad -> %pad\n", + dma_name, &cfg.src_addr, &cfg.dst_addr); dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, (void *)id, dev, diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 46677af6c748..73ce4c90efda 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -168,7 +168,7 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv, * SSI : 0xec541000 / 0xec241008 / 0xec24100c * SSIU: 0xec541000 / 0xec100000 / 0xec100000 / 0xec400000 / 0xec400000 * SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000 - * CMD : 0xec500000 / 0xec008000 0xec308000 + * 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) @@ -188,14 +188,13 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv, #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 void rsnd_gen2_dma_addr(struct rsnd_priv *priv, - struct rsnd_dma *dma, - struct dma_slave_config *cfg, - int is_play, int slave_id) +static dma_addr_t +rsnd_gen2_dma_addr(struct rsnd_priv *priv, + struct rsnd_mod *mod, + int is_play, int is_from) { struct platform_device *pdev = rsnd_priv_to_pdev(priv); struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_mod *mod = rsnd_dma_to_mod(dma); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); dma_addr_t ssi_reg = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSI)->start; @@ -206,76 +205,68 @@ static void rsnd_gen2_dma_addr(struct rsnd_priv *priv, int use_dvc = !!rsnd_io_to_mod_dvc(io); int id = rsnd_mod_id(mod); struct dma_addr { - dma_addr_t src_addr; - dma_addr_t dst_addr; + dma_addr_t out_addr; + dma_addr_t in_addr; } dma_addrs[3][2][3] = { /* SRC */ {{{ 0, 0 }, /* Capture */ - { RDMA_SRC_O_N(src, id), 0 }, - { RDMA_CMD_O_N(src, id), 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, }, - { 0, RDMA_SRC_I_N(src, id) }, - { 0, RDMA_SRC_I_N(src, id) } } + { 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 }, - { 0, 0 }, - { 0, 0 } }, + { RDMA_SSIU_O_P(ssi, id), 0 }, + { RDMA_SSIU_O_P(ssi, id), 0 } }, /* Playback */ {{ 0, RDMA_SSI_I_N(ssi, id) }, - { 0, 0 }, - { 0, 0 } } + { 0, RDMA_SSIU_I_P(ssi, id) }, + { 0, RDMA_SSIU_I_P(ssi, id) } } }, /* SSIU */ /* Capture */ {{{ RDMA_SSIU_O_N(ssi, id), 0 }, - { RDMA_SSIU_O_P(ssi, id), RDMA_SRC_I_P(src, id) }, - { RDMA_SSIU_O_P(ssi, id), RDMA_SRC_I_P(src, id) } }, + { RDMA_SSIU_O_P(ssi, id), 0 }, + { RDMA_SSIU_O_P(ssi, id), 0 } }, /* Playback */ {{ 0, RDMA_SSIU_I_N(ssi, id) }, - { RDMA_SRC_O_P(src, id), RDMA_SSIU_I_P(ssi, id) }, - { RDMA_CMD_O_P(src, id), RDMA_SSIU_I_P(ssi, id) } } }, + { 0, RDMA_SSIU_I_P(ssi, id) }, + { 0, RDMA_SSIU_I_P(ssi, id) } } }, }; /* it shouldn't happen */ - if (use_dvc & !use_src) { + if (use_dvc & !use_src) dev_err(dev, "DVC is selected without SRC\n"); - return; - } /* use SSIU or SSI ? */ if (is_ssi && (0 == strcmp(rsnd_mod_dma_name(mod), "ssiu"))) is_ssi++; - cfg->src_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].src_addr; - cfg->dst_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].dst_addr; - - dev_dbg(dev, "dma%d addr - src : %x / dst : %x\n", - id, cfg->src_addr, cfg->dst_addr); + return (is_from) ? + dma_addrs[is_ssi][is_play][use_src + use_dvc].out_addr : + dma_addrs[is_ssi][is_play][use_src + use_dvc].in_addr; } -void rsnd_gen_dma_addr(struct rsnd_priv *priv, - struct rsnd_dma *dma, - struct dma_slave_config *cfg, - int is_play, int slave_id) +dma_addr_t rsnd_gen_dma_addr(struct rsnd_priv *priv, + struct rsnd_mod *mod, + int is_play, int is_from) { - cfg->slave_id = slave_id; - cfg->src_addr = 0; - cfg->dst_addr = 0; - cfg->direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; - /* * gen1 uses default DMA addr */ if (rsnd_is_gen1(priv)) - return; + return 0; - rsnd_gen2_dma_addr(priv, dma, cfg, is_play, slave_id); -} + if (!mod) + return 0; + return rsnd_gen2_dma_addr(priv, mod, is_play, is_from); +} /* * Gen2 diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 60b5e9260600..425b22ee6fb9 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -279,10 +279,9 @@ int rsnd_gen_probe(struct platform_device *pdev, void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg); -void rsnd_gen_dma_addr(struct rsnd_priv *priv, - struct rsnd_dma *dma, - struct dma_slave_config *cfg, - int is_play, int slave_id); +dma_addr_t rsnd_gen_dma_addr(struct rsnd_priv *priv, + struct rsnd_mod *mod, + int is_play, int is_from); #define rsnd_is_gen1(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1) #define rsnd_is_gen2(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2) -- cgit v1.2.3 From 340371005d399b595f4044fc5e336f4a66ead101 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 22 Jun 2014 17:59:02 -0700 Subject: ASoC: rsnd: DMA start address is properly used for each DMAC R-Car sound uses Audio DMAC and Audio DMAC peri peri. Audio DMAC peri peri transfers data inside circuit. DMA transfer needs source / destination address, and destination address can be set via dmaengine_slave_config(). The source address can be set when starting DMAEngine. Because Audio DMAC peri peri always ignores its value, current driver always used same source address for Audio DMAC / Audio DMAC peri peri (Audio DMAC peri peri source / destination address is always fixed value) But, This is not good match for DT booting. This patch properly uses DMA start address for Audio DMAC / Audio DMAC peri peri. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 2 ++ sound/soc/sh/rcar/rsnd.h | 1 + 2 files changed, 3 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 4435a31ecdad..49d9b31b185c 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -200,6 +200,7 @@ void rsnd_dma_start(struct rsnd_dma *dma) struct dma_async_tx_descriptor *desc; desc = dmaengine_prep_dma_cyclic(dma->chan, + (dma->addr) ? dma->addr : substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream), @@ -347,6 +348,7 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, if (ret < 0) goto rsnd_dma_init_err; + dma->addr = is_play ? cfg.src_addr : cfg.dst_addr; dma->dir = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; return 0; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 425b22ee6fb9..631b149df08f 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -158,6 +158,7 @@ struct rsnd_dma { struct sh_dmae_slave slave; struct dma_chan *chan; enum dma_transfer_direction dir; + dma_addr_t addr; }; void rsnd_dma_start(struct rsnd_dma *dma); -- cgit v1.2.3 From 34cb6123f90d264d63bdcd3ee0df0d2cb4b36aab Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 22 Jun 2014 17:59:28 -0700 Subject: ASoC: rsnd: add DT support to DVC Now, DVC can use DT Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 13 +++++++++++-- sound/soc/sh/rcar/dvc.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 49d9b31b185c..907d4802fd5c 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -286,7 +286,13 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, mod[i] = src; src = NULL; } else { - mod[i] = dvc; + if ((!is_play) && (this == src)) + this = dvc; + + mod[i] = (is_play) ? src : dvc; + i++; + mod[i] = (is_play) ? dvc : src; + src = NULL; dvc = NULL; } @@ -719,12 +725,13 @@ static void rsnd_of_parse_dai(struct platform_device *pdev, struct device_node *dai_node, *dai_np; struct device_node *ssi_node, *ssi_np; struct device_node *src_node, *src_np; + struct device_node *dvc_node, *dvc_np; struct device_node *playback, *capture; struct rsnd_dai_platform_info *dai_info; struct rcar_snd_info *info = rsnd_priv_to_info(priv); struct device *dev = &pdev->dev; int nr, i; - int dai_i, ssi_i, src_i; + int dai_i, ssi_i, src_i, dvc_i; if (!of_data) return; @@ -750,6 +757,7 @@ static void rsnd_of_parse_dai(struct platform_device *pdev, ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi"); src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src"); + dvc_node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc"); #define mod_parse(name) \ if (name##_node) { \ @@ -785,6 +793,7 @@ if (name##_node) { \ mod_parse(ssi); mod_parse(src); + mod_parse(dvc); if (playback) of_node_put(playback); diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index deef310c75dc..9096fb03d001 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -235,6 +235,42 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) return &((struct rsnd_dvc *)(priv->dvc) + id)->mod; } +static void rsnd_of_parse_dvc(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv) +{ + struct device_node *node; + struct rsnd_dvc_platform_info *dvc_info; + struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device *dev = &pdev->dev; + int nr; + + if (!of_data) + return; + + node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc"); + if (!node) + return; + + nr = of_get_child_count(node); + if (!nr) + goto rsnd_of_parse_dvc_end; + + dvc_info = devm_kzalloc(dev, + sizeof(struct rsnd_dvc_platform_info) * nr, + GFP_KERNEL); + if (!dvc_info) { + dev_err(dev, "dvc info allocation error\n"); + goto rsnd_of_parse_dvc_end; + } + + info->dvc_info = dvc_info; + info->dvc_info_nr = nr; + +rsnd_of_parse_dvc_end: + of_node_put(node); +} + int rsnd_dvc_probe(struct platform_device *pdev, const struct rsnd_of_data *of_data, struct rsnd_priv *priv) @@ -246,6 +282,8 @@ int rsnd_dvc_probe(struct platform_device *pdev, char name[RSND_DVC_NAME_SIZE]; int i, nr; + rsnd_of_parse_dvc(pdev, of_data, priv); + nr = info->dvc_info_nr; if (!nr) return 0; -- cgit v1.2.3 From 2bf865ba30405056e7922b960a1687bb4d5a4999 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 16 Jul 2014 23:18:44 -0700 Subject: ASoC: rsnd: add missing src/dst_addr_width for DMAEngine Renesas new DMAEngine driver requests src/dst_addr_width Signed-off-by: Kuninori Morimoto Acked-by: Laurent Pinchart Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 907d4802fd5c..c48d999a3fce 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -338,6 +338,8 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; cfg.src_addr = rsnd_gen_dma_addr(priv, mod_from, is_play, 1); cfg.dst_addr = rsnd_gen_dma_addr(priv, mod_to, is_play, 0); + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; dev_dbg(dev, "dma : %s %pad -> %pad\n", dma_name, &cfg.src_addr, &cfg.dst_addr); -- cgit v1.2.3 From d62a3dcd4d75b1713d12697afdbffaf9a9da8f43 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 24 Jul 2014 01:51:31 -0700 Subject: ASoC: rsnd: fixup dai remove callback operation rsnd driver is using SSI/SRC/DVC which are using "mod" base operation. These "mod" are supporting "probe" and "remove" callbacks. Current rsnd_probe should call "remove" if "probe" was failed, since "probe" might be having DMAEngine handle. Some mod's "remove" callback might be called without calling "probe", but it is no problem. because "remove" do nothing in such case. So, all mod's "remove" should be called when error case of rsnd_probe() and rsnd_remove(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index c48d999a3fce..f07742f1eb11 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1043,11 +1043,11 @@ static int rsnd_probe(struct platform_device *pdev) for_each_rsnd_dai(rdai, priv, i) { ret = rsnd_dai_call(probe, &rdai->playback, rdai); if (ret) - return ret; + goto exit_snd_probe; ret = rsnd_dai_call(probe, &rdai->capture, rdai); if (ret) - return ret; + goto exit_snd_probe; } /* @@ -1075,6 +1075,11 @@ static int rsnd_probe(struct platform_device *pdev) exit_snd_soc: snd_soc_unregister_platform(dev); +exit_snd_probe: + for_each_rsnd_dai(rdai, priv, i) { + rsnd_dai_call(remove, &rdai->playback, rdai); + rsnd_dai_call(remove, &rdai->capture, rdai); + } return ret; } @@ -1083,21 +1088,16 @@ static int rsnd_remove(struct platform_device *pdev) { struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); struct rsnd_dai *rdai; - int ret, i; + int ret = 0, i; pm_runtime_disable(&pdev->dev); for_each_rsnd_dai(rdai, priv, i) { - ret = rsnd_dai_call(remove, &rdai->playback, rdai); - if (ret) - return ret; - - ret = rsnd_dai_call(remove, &rdai->capture, rdai); - if (ret) - return ret; + ret |= rsnd_dai_call(remove, &rdai->playback, rdai); + ret |= rsnd_dai_call(remove, &rdai->capture, rdai); } - return 0; + return ret; } static struct platform_driver rsnd_driver = { -- cgit v1.2.3 From b8c637864a6904a9ba8e0df556d5bdf9f26b2c54 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 29 Jul 2014 00:37:31 -0700 Subject: ASoC: rsnd: use regmap_mmio instead of original regmap bus Current rsnd driver is using regmap and regmap_field. It used original regmap bus which is single regmap instance for multi register mapping. This patch modifies it to use regmap_mmio bus, and tidyuped probe method Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/Kconfig | 2 +- sound/soc/sh/rcar/gen.c | 439 +++++++++++++++++++++--------------------------- 2 files changed, 189 insertions(+), 252 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index b43fdf0d08af..80245b6eebd6 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -37,7 +37,7 @@ config SND_SOC_SH4_SIU config SND_SOC_RCAR tristate "R-Car series SRU/SCU/SSIU/SSI support" select SND_SIMPLE_CARD - select REGMAP + select REGMAP_MMIO help This option enables R-Car SUR/SCU/SSIU/SSI sound support diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 73ce4c90efda..5f9e0722abcf 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -15,63 +15,35 @@ struct rsnd_gen { struct rsnd_gen_ops *ops; - struct regmap *regmap; + struct regmap *regmap[RSND_BASE_MAX]; struct regmap_field *regs[RSND_REG_MAX]; }; #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) -#define RSND_REG_SET(gen, id, reg_id, offset, _id_offset, _id_size) \ - [id] = { \ - .reg = (unsigned int)gen->base[reg_id] + offset, \ - .lsb = 0, \ - .msb = 31, \ - .id_size = _id_size, \ - .id_offset = _id_offset, \ - } - -/* - * basic function - */ -static int rsnd_regmap_write32(void *context, const void *_data, size_t count) -{ - struct rsnd_priv *priv = context; - struct device *dev = rsnd_priv_to_dev(priv); - u32 *data = (u32 *)_data; - u32 val = data[1]; - void __iomem *reg = (void *)data[0]; - - iowrite32(val, reg); - - dev_dbg(dev, "w %p : %08x\n", reg, val); - - return 0; -} - -static int rsnd_regmap_read32(void *context, - const void *_data, size_t reg_size, - void *_val, size_t val_size) -{ - struct rsnd_priv *priv = context; - struct device *dev = rsnd_priv_to_dev(priv); - u32 *data = (u32 *)_data; - u32 *val = (u32 *)_val; - void __iomem *reg = (void *)data[0]; - - *val = ioread32(reg); - - dev_dbg(dev, "r %p : %08x\n", reg, *val); +struct rsnd_regmap_field_conf { + int idx; + unsigned int reg_offset; + unsigned int id_offset; +}; - return 0; +#define RSND_REG_SET(id, offset, _id_offset) \ +{ \ + .idx = id, \ + .reg_offset = offset, \ + .id_offset = _id_offset, \ } +/* single address mapping */ +#define RSND_GEN_S_REG(id, offset) \ + RSND_REG_SET(RSND_REG_##id, offset, 0) -static struct regmap_bus rsnd_regmap_bus = { - .write = rsnd_regmap_write32, - .read = rsnd_regmap_read32, - .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, - .val_format_endian_default = REGMAP_ENDIAN_NATIVE, -}; +/* multi address mapping */ +#define RSND_GEN_M_REG(id, offset, _id_offset) \ + RSND_REG_SET(RSND_REG_##id, offset, _id_offset) +/* + * basic function + */ static int rsnd_is_accessible_reg(struct rsnd_priv *priv, struct rsnd_gen *gen, enum rsnd_reg reg) { @@ -88,6 +60,7 @@ static int rsnd_is_accessible_reg(struct rsnd_priv *priv, u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg) { + struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_gen *gen = rsnd_priv_to_gen(priv); u32 val; @@ -96,6 +69,8 @@ u32 rsnd_read(struct rsnd_priv *priv, regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); + dev_dbg(dev, "r %s - 0x%04d : %08x\n", rsnd_mod_name(mod), reg, val); + return val; } @@ -103,12 +78,15 @@ void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 data) { + 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_write(gen->regs[reg], rsnd_mod_id(mod), data); + + dev_dbg(dev, "w %s - 0x%04d : %08x\n", rsnd_mod_name(mod), reg, data); } void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, @@ -123,33 +101,58 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, mask, data); } -static int rsnd_gen_regmap_init(struct rsnd_priv *priv, - struct rsnd_gen *gen, - struct reg_field *regf) +#define rsnd_gen_regmap_init(priv, id_size, reg_id, conf) \ + _rsnd_gen_regmap_init(priv, id_size, reg_id, conf, ARRAY_SIZE(conf)) +static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, + int id_size, + int reg_id, + struct rsnd_regmap_field_conf *conf, + int conf_size) { - int i; + 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; - gen->regmap = devm_regmap_init(dev, &rsnd_regmap_bus, priv, ®c); - if (IS_ERR(gen->regmap)) { - dev_err(dev, "regmap error %ld\n", PTR_ERR(gen->regmap)); - return PTR_ERR(gen->regmap); - } + 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); - for (i = 0; i < RSND_REG_MAX; i++) { - gen->regs[i] = NULL; - if (!regf[i].reg) - continue; + regmap = devm_regmap_init_mmio(dev, base, ®c); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); - gen->regs[i] = devm_regmap_field_alloc(dev, gen->regmap, regf[i]); - if (IS_ERR(gen->regs[i])) - return PTR_ERR(gen->regs[i]); + gen->base[reg_id] = base; + gen->regmap[reg_id] = regmap; + 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); + + gen->regs[conf[i].idx] = regs; } return 0; @@ -271,119 +274,85 @@ dma_addr_t rsnd_gen_dma_addr(struct rsnd_priv *priv, /* * Gen2 */ - -/* single address mapping */ -#define RSND_GEN2_S_REG(gen, reg, id, offset) \ - RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN2_##reg, offset, 0, 10) - -/* multi address mapping */ -#define RSND_GEN2_M_REG(gen, reg, id, offset, _id_offset) \ - RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN2_##reg, offset, _id_offset, 10) - -static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) -{ - struct reg_field regf[RSND_REG_MAX] = { - RSND_GEN2_S_REG(gen, SSIU, SSI_MODE0, 0x800), - RSND_GEN2_S_REG(gen, SSIU, SSI_MODE1, 0x804), - /* FIXME: it needs SSI_MODE2/3 in the future */ - RSND_GEN2_M_REG(gen, SSIU, SSI_BUSIF_MODE, 0x0, 0x80), - RSND_GEN2_M_REG(gen, SSIU, SSI_BUSIF_ADINR,0x4, 0x80), - RSND_GEN2_M_REG(gen, SSIU, SSI_CTRL, 0x10, 0x80), - RSND_GEN2_M_REG(gen, SSIU, INT_ENABLE, 0x18, 0x80), - - RSND_GEN2_M_REG(gen, SCU, SRC_BUSIF_MODE, 0x0, 0x20), - RSND_GEN2_M_REG(gen, SCU, SRC_ROUTE_MODE0,0xc, 0x20), - RSND_GEN2_M_REG(gen, SCU, SRC_CTRL, 0x10, 0x20), - RSND_GEN2_M_REG(gen, SCU, CMD_ROUTE_SLCT, 0x18c, 0x20), - RSND_GEN2_M_REG(gen, SCU, CMD_CTRL, 0x190, 0x20), - RSND_GEN2_M_REG(gen, SCU, SRC_SWRSR, 0x200, 0x40), - RSND_GEN2_M_REG(gen, SCU, SRC_SRCIR, 0x204, 0x40), - RSND_GEN2_M_REG(gen, SCU, SRC_ADINR, 0x214, 0x40), - RSND_GEN2_M_REG(gen, SCU, SRC_IFSCR, 0x21c, 0x40), - RSND_GEN2_M_REG(gen, SCU, SRC_IFSVR, 0x220, 0x40), - RSND_GEN2_M_REG(gen, SCU, SRC_SRCCR, 0x224, 0x40), - RSND_GEN2_M_REG(gen, SCU, SRC_BSDSR, 0x22c, 0x40), - RSND_GEN2_M_REG(gen, SCU, SRC_BSISR, 0x238, 0x40), - RSND_GEN2_M_REG(gen, SCU, DVC_SWRSR, 0xe00, 0x100), - RSND_GEN2_M_REG(gen, SCU, DVC_DVUIR, 0xe04, 0x100), - RSND_GEN2_M_REG(gen, SCU, DVC_ADINR, 0xe08, 0x100), - RSND_GEN2_M_REG(gen, SCU, DVC_DVUCR, 0xe10, 0x100), - RSND_GEN2_M_REG(gen, SCU, DVC_ZCMCR, 0xe14, 0x100), - RSND_GEN2_M_REG(gen, SCU, DVC_VOL0R, 0xe28, 0x100), - RSND_GEN2_M_REG(gen, SCU, DVC_VOL1R, 0xe2c, 0x100), - RSND_GEN2_M_REG(gen, SCU, DVC_DVUER, 0xe48, 0x100), - - RSND_GEN2_S_REG(gen, ADG, BRRA, 0x00), - RSND_GEN2_S_REG(gen, ADG, BRRB, 0x04), - RSND_GEN2_S_REG(gen, ADG, SSICKR, 0x08), - RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c), - RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10), - RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL2, 0x14), - RSND_GEN2_S_REG(gen, ADG, DIV_EN, 0x30), - RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL0, 0x34), - RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL1, 0x38), - RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL2, 0x3c), - RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL3, 0x40), - RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL4, 0x44), - RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL0, 0x48), - RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL1, 0x4c), - RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL2, 0x50), - RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL3, 0x54), - RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL4, 0x58), - RSND_GEN2_S_REG(gen, ADG, CMDOUT_TIMSEL, 0x5c), - - RSND_GEN2_M_REG(gen, SSI, SSICR, 0x00, 0x40), - RSND_GEN2_M_REG(gen, SSI, SSISR, 0x04, 0x40), - RSND_GEN2_M_REG(gen, SSI, SSITDR, 0x08, 0x40), - RSND_GEN2_M_REG(gen, SSI, SSIRDR, 0x0c, 0x40), - RSND_GEN2_M_REG(gen, SSI, SSIWSR, 0x20, 0x40), - }; - - return rsnd_gen_regmap_init(priv, gen, regf); -} - static int rsnd_gen2_probe(struct platform_device *pdev, struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - struct resource *scu_res; - struct resource *adg_res; - struct resource *ssiu_res; - struct resource *ssi_res; - int ret; - - /* - * map address - */ - scu_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SCU); - adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_ADG); - ssiu_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSIU); - ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSI); - - gen->base[RSND_GEN2_SCU] = devm_ioremap_resource(dev, scu_res); - gen->base[RSND_GEN2_ADG] = devm_ioremap_resource(dev, adg_res); - gen->base[RSND_GEN2_SSIU] = devm_ioremap_resource(dev, ssiu_res); - gen->base[RSND_GEN2_SSI] = devm_ioremap_resource(dev, ssi_res); - if (IS_ERR(gen->base[RSND_GEN2_SCU]) || - IS_ERR(gen->base[RSND_GEN2_ADG]) || - IS_ERR(gen->base[RSND_GEN2_SSIU]) || - IS_ERR(gen->base[RSND_GEN2_SSI])) - return -ENODEV; - - ret = rsnd_gen2_regmap_init(priv, gen); - if (ret < 0) - return ret; - - dev_dbg(dev, "Gen2 device probed\n"); - dev_dbg(dev, "SCU : %pap => %p\n", &scu_res->start, - gen->base[RSND_GEN2_SCU]); - dev_dbg(dev, "ADG : %pap => %p\n", &adg_res->start, - gen->base[RSND_GEN2_ADG]); - dev_dbg(dev, "SSIU : %pap => %p\n", &ssiu_res->start, - gen->base[RSND_GEN2_SSIU]); - dev_dbg(dev, "SSI : %pap => %p\n", &ssi_res->start, - gen->base[RSND_GEN2_SSI]); + struct rsnd_regmap_field_conf conf_ssiu[] = { + RSND_GEN_S_REG(SSI_MODE0, 0x800), + RSND_GEN_S_REG(SSI_MODE1, 0x804), + /* FIXME: it needs SSI_MODE2/3 in the future */ + RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80), + RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80), + RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), + RSND_GEN_M_REG(INT_ENABLE, 0x18, 0x80), + }; + struct rsnd_regmap_field_conf conf_scu[] = { + RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x0, 0x20), + RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20), + RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20), + RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20), + RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20), + 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(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_VOL0R, 0xe28, 0x100), + RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100), + RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100), + }; + struct rsnd_regmap_field_conf conf_adg[] = { + RSND_GEN_S_REG(BRRA, 0x00), + RSND_GEN_S_REG(BRRB, 0x04), + RSND_GEN_S_REG(SSICKR, 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), + }; + 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, conf_ssiu); + ret_scu = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_SCU, conf_scu); + ret_adg = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_ADG, conf_adg); + ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_GEN2_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; + + dev_dbg(dev, "Gen2 is probed\n"); return 0; } @@ -392,92 +361,60 @@ static int rsnd_gen2_probe(struct platform_device *pdev, * Gen1 */ -/* single address mapping */ -#define RSND_GEN1_S_REG(gen, reg, id, offset) \ - RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN1_##reg, offset, 0, 9) - -/* multi address mapping */ -#define RSND_GEN1_M_REG(gen, reg, id, offset, _id_offset) \ - RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN1_##reg, offset, _id_offset, 9) - -static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) -{ - struct reg_field regf[RSND_REG_MAX] = { - RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_SEL, 0x00), - RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL0, 0x08), - RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL1, 0x0c), - RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL2, 0x10), - RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_CTRL, 0xc0), - RSND_GEN1_S_REG(gen, SRU, SSI_MODE0, 0xD0), - RSND_GEN1_S_REG(gen, SRU, SSI_MODE1, 0xD4), - RSND_GEN1_M_REG(gen, SRU, SRC_BUSIF_MODE, 0x20, 0x4), - RSND_GEN1_M_REG(gen, SRU, SRC_ROUTE_MODE0,0x50, 0x8), - RSND_GEN1_M_REG(gen, SRU, SRC_SWRSR, 0x200, 0x40), - RSND_GEN1_M_REG(gen, SRU, SRC_SRCIR, 0x204, 0x40), - RSND_GEN1_M_REG(gen, SRU, SRC_ADINR, 0x214, 0x40), - RSND_GEN1_M_REG(gen, SRU, SRC_IFSCR, 0x21c, 0x40), - RSND_GEN1_M_REG(gen, SRU, SRC_IFSVR, 0x220, 0x40), - RSND_GEN1_M_REG(gen, SRU, SRC_SRCCR, 0x224, 0x40), - RSND_GEN1_M_REG(gen, SRU, SRC_MNFSR, 0x228, 0x40), - - RSND_GEN1_S_REG(gen, ADG, BRRA, 0x00), - RSND_GEN1_S_REG(gen, ADG, BRRB, 0x04), - RSND_GEN1_S_REG(gen, ADG, SSICKR, 0x08), - RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c), - RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10), - RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL3, 0x18), - RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL4, 0x1c), - RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL5, 0x20), - - RSND_GEN1_M_REG(gen, SSI, SSICR, 0x00, 0x40), - RSND_GEN1_M_REG(gen, SSI, SSISR, 0x04, 0x40), - RSND_GEN1_M_REG(gen, SSI, SSITDR, 0x08, 0x40), - RSND_GEN1_M_REG(gen, SSI, SSIRDR, 0x0c, 0x40), - RSND_GEN1_M_REG(gen, SSI, SSIWSR, 0x20, 0x40), - }; - - return rsnd_gen_regmap_init(priv, gen, regf); -} - static int rsnd_gen1_probe(struct platform_device *pdev, struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - struct resource *sru_res; - struct resource *adg_res; - struct resource *ssi_res; - int ret; - - /* - * map address - */ - sru_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU); - adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_ADG); - ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SSI); - - gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res); - gen->base[RSND_GEN1_ADG] = devm_ioremap_resource(dev, adg_res); - gen->base[RSND_GEN1_SSI] = devm_ioremap_resource(dev, ssi_res); - if (IS_ERR(gen->base[RSND_GEN1_SRU]) || - IS_ERR(gen->base[RSND_GEN1_ADG]) || - IS_ERR(gen->base[RSND_GEN1_SSI])) - return -ENODEV; + struct rsnd_regmap_field_conf conf_sru[] = { + RSND_GEN_S_REG(SRC_ROUTE_SEL, 0x00), + RSND_GEN_S_REG(SRC_TMG_SEL0, 0x08), + RSND_GEN_S_REG(SRC_TMG_SEL1, 0x0c), + RSND_GEN_S_REG(SRC_TMG_SEL2, 0x10), + RSND_GEN_S_REG(SRC_ROUTE_CTRL, 0xc0), + RSND_GEN_S_REG(SSI_MODE0, 0xD0), + RSND_GEN_S_REG(SSI_MODE1, 0xD4), + RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x20, 0x4), + RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0x50, 0x8), + 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_MNFSR, 0x228, 0x40), + }; + struct rsnd_regmap_field_conf conf_adg[] = { + RSND_GEN_S_REG(BRRA, 0x00), + RSND_GEN_S_REG(BRRB, 0x04), + RSND_GEN_S_REG(SSICKR, 0x08), + RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), + RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), + RSND_GEN_S_REG(AUDIO_CLK_SEL3, 0x18), + RSND_GEN_S_REG(AUDIO_CLK_SEL4, 0x1c), + RSND_GEN_S_REG(AUDIO_CLK_SEL5, 0x20), + }; + 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_sru; + int ret_adg; + int ret_ssi; - ret = rsnd_gen1_regmap_init(priv, gen); - if (ret < 0) - return ret; + ret_sru = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SRU, conf_sru); + ret_adg = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, conf_adg); + ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, conf_ssi); + if (ret_sru < 0 || + ret_adg < 0 || + ret_ssi < 0) + return ret_sru | ret_adg | ret_ssi; - dev_dbg(dev, "Gen1 device probed\n"); - dev_dbg(dev, "SRU : %pap => %p\n", &sru_res->start, - gen->base[RSND_GEN1_SRU]); - dev_dbg(dev, "ADG : %pap => %p\n", &adg_res->start, - gen->base[RSND_GEN1_ADG]); - dev_dbg(dev, "SSI : %pap => %p\n", &ssi_res->start, - gen->base[RSND_GEN1_SSI]); + dev_dbg(dev, "Gen1 is probed\n"); return 0; - } /* -- cgit v1.2.3 From 054cd7f4b986a941b56372b743602f7df6569c98 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 30 Jul 2014 23:52:04 -0700 Subject: ASoC: rsnd: care detail of SRC_BSDSR Driver should care more detail of SRC_BSDSR settings. The sound includes noise without this patch if it used SRC. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 4d39505c21cf..1ef811a26bd7 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -483,15 +483,45 @@ static struct rsnd_mod_ops rsnd_src_gen1_ops = { static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, struct rsnd_dai *rdai) { + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_src *src = rsnd_mod_to_src(mod); + uint ratio; int ret; + /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ + if (!rsnd_src_convert_rate(src)) + ratio = 0; + else if (rsnd_src_convert_rate(src) > runtime->rate) + ratio = 100 * rsnd_src_convert_rate(src) / runtime->rate; + else + ratio = 100 * runtime->rate / rsnd_src_convert_rate(src); + + if (ratio > 600) { + dev_err(dev, "FSO/FSI ratio error\n"); + return -EINVAL; + } + ret = rsnd_src_set_convert_rate(mod, rdai); if (ret < 0) return ret; rsnd_mod_write(mod, SRC_SRCCR, 0x00011110); - rsnd_mod_write(mod, SRC_BSDSR, 0x01800000); + switch (rsnd_mod_id(mod)) { + case 5: + case 6: + case 7: + case 8: + rsnd_mod_write(mod, SRC_BSDSR, 0x02400000); + break; + default: + rsnd_mod_write(mod, SRC_BSDSR, 0x01800000); + break; + } + rsnd_mod_write(mod, SRC_BSISR, 0x00100060); return 0; -- cgit v1.2.3 From 1cc7195929501b96fccce42646f1ad0ffe2598a6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 30 Jul 2014 23:52:26 -0700 Subject: ASoC: rsnd: care audio local bus data format consistency R-Car sound uses Audio Local Bus which uses Lch/Rch format. This bus is used if driver uses BUSIF. But sound data is written as Rch/Lch format in register. This means Rch <-> Lch will be inverted. SSIU :: BUSIF_DALIGN is used to controlling data format. Reported-by: Jun Watanabe Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/gen.c | 1 + sound/soc/sh/rcar/rsnd.h | 2 ++ sound/soc/sh/rcar/src.c | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 5f9e0722abcf..5db055750991 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -284,6 +284,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev, /* FIXME: it needs SSI_MODE2/3 in the future */ RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80), RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80), + RSND_GEN_M_REG(BUSIF_DALIGN, 0x8, 0x80), RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), RSND_GEN_M_REG(INT_ENABLE, 0x18, 0x80), }; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 631b149df08f..d119adf97c9c 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -90,6 +90,7 @@ enum rsnd_reg { RSND_REG_SHARE19, RSND_REG_SHARE20, RSND_REG_SHARE21, + RSND_REG_SHARE22, RSND_REG_MAX, }; @@ -127,6 +128,7 @@ enum rsnd_reg { #define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19 #define RSND_REG_CMD_CTRL RSND_REG_SHARE20 #define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21 +#define RSND_REG_BUSIF_DALIGN RSND_REG_SHARE22 struct rsnd_of_data; struct rsnd_priv; diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 1ef811a26bd7..9183e0145503 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -110,6 +110,8 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, struct rsnd_dai *rdai, int use_busif) { + struct rsnd_dai_stream *io = rsnd_mod_to_io(ssi_mod); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); int ssi_id = rsnd_mod_id(ssi_mod); /* @@ -146,10 +148,27 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, * DMA settings for SSIU */ if (use_busif) { + u32 val = 0x76543210; + u32 mask = ~0; + rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR, rsnd_get_adinr(ssi_mod)); 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); + } return 0; -- cgit v1.2.3 From 4f8f86aa41232cc4595136f18013324482fdf749 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 30 Jul 2014 23:52:50 -0700 Subject: ASoC: rsnd: add missing dev_dbg() in rsnd_bset() b8c637864a6904a9ba8e0df556d5bdf9f26b2c54 (ASoC: rsnd: use regmap_mmio instead of original regmap bus) used regmap_mmio and modified dev_dbg() for rsnd_read/write(). But rsnd_bset() is missing it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/gen.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 5db055750991..3fdf3be7b99a 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -92,6 +92,7 @@ void rsnd_write(struct rsnd_priv *priv, void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data) { + 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)) @@ -99,6 +100,9 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), mask, data); + + dev_dbg(dev, "b %s - 0x%04d : %08x/%08x\n", + rsnd_mod_name(mod), reg, data, mask); } #define rsnd_gen_regmap_init(priv, id_size, reg_id, conf) \ -- cgit v1.2.3 From 7c63f3c02f5a998621758239abed43c5bd454b70 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 30 Jul 2014 23:53:03 -0700 Subject: ASoC: rsnd: fixup pcm_new callback method bff58ea4f43d9b4a9fd6fb05fabc8f50f68131f5 (ASoC: rsnd: add DVC support) added DVC support, and it added pcm_new callback feature for it. Then it called all DAI's pcm_new callback, and it was wrong. This patch fixup it and call correct callback. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f07742f1eb11..d7c669790dd4 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -944,19 +944,17 @@ static struct snd_pcm_ops rsnd_pcm_ops = { static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd) { - struct rsnd_priv *priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); - struct rsnd_dai *rdai; - int i, ret; + struct snd_soc_dai *dai = rtd->cpu_dai; + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + int ret; - for_each_rsnd_dai(rdai, priv, i) { - ret = rsnd_dai_call(pcm_new, &rdai->playback, rdai, rtd); - if (ret) - return ret; + ret = rsnd_dai_call(pcm_new, &rdai->playback, rdai, rtd); + if (ret) + return ret; - ret = rsnd_dai_call(pcm_new, &rdai->capture, rdai, rtd); - if (ret) - return ret; - } + ret = rsnd_dai_call(pcm_new, &rdai->capture, rdai, rtd); + if (ret) + return ret; return snd_pcm_lib_preallocate_pages_for_all( rtd->pcm, -- cgit v1.2.3 From 1a7889ca8aba333d7c74fad543d692c31bc7f280 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 31 Jul 2014 18:08:18 -0700 Subject: ASoC: rsnd: fixup SND_SOC_DAIFMT_xB_xF behavior In current R-Car rsnd driver, the SND_SOC_DAIFMT_xB_xF flags are used to HW default behavior, but, it should be used to specific format. The waveforms of LEFT_J/RIGHT_J format with SND_SOC_DAIFMT_NB_NF flag will be started from "falling edge" without this patch. But, it should be started from "rising edge". Reported-by: Jun Watanabe Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index d7c669790dd4..19f78963e8b9 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -624,40 +624,41 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - /* set clock inversion */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_IF: - rdai->bit_clk_inv = 0; - rdai->frm_clk_inv = 1; - break; - case SND_SOC_DAIFMT_IB_NF: - rdai->bit_clk_inv = 1; - rdai->frm_clk_inv = 0; - break; - case SND_SOC_DAIFMT_IB_IF: - rdai->bit_clk_inv = 1; - rdai->frm_clk_inv = 1; - break; - case SND_SOC_DAIFMT_NB_NF: - default: - rdai->bit_clk_inv = 0; - rdai->frm_clk_inv = 0; - break; - } - /* set format */ 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: 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; + } + + /* set clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_IF: + rdai->bit_clk_inv = rdai->bit_clk_inv; + rdai->frm_clk_inv = !rdai->frm_clk_inv; + break; + case SND_SOC_DAIFMT_IB_NF: + rdai->bit_clk_inv = !rdai->bit_clk_inv; + rdai->frm_clk_inv = rdai->frm_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; } -- cgit v1.2.3 From 486b09c750e58777976ad74a37de7b4252630332 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 1 Aug 2014 03:10:47 -0700 Subject: ASoC: rsnd: tidyup DVC control method DVC can use Volume and Mute control, and these control methods doesn't have much difference. This patch cleanup current method, and it will be used for Mute control. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dvc.c | 59 ++++++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 25 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 9096fb03d001..12a0a2068d34 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -20,7 +20,7 @@ struct rsnd_dvc { struct rsnd_dvc_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; struct clk *clk; - long volume[RSND_DVC_VOLUME_NUM]; + u8 volume[RSND_DVC_VOLUME_NUM]; }; #define rsnd_mod_to_dvc(_mod) \ @@ -151,12 +151,11 @@ static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl, static int rsnd_dvc_volume_get(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *ucontrol) { - struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); - struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + u8 *val = (u8 *)kctrl->private_value; int i; for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) - ucontrol->value.integer.value[i] = dvc->volume[i]; + ucontrol->value.integer.value[i] = val[i]; return 0; } @@ -165,47 +164,38 @@ static int rsnd_dvc_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *ucontrol) { struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); - struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + u8 *val = (u8 *)kctrl->private_value; int i, change = 0; for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) { - if (ucontrol->value.integer.value[i] < 0 || - ucontrol->value.integer.value[i] > RSND_DVC_VOLUME_MAX) - return -EINVAL; - - change |= (ucontrol->value.integer.value[i] != dvc->volume[i]); + change |= (ucontrol->value.integer.value[i] != val[i]); + val[i] = ucontrol->value.integer.value[i]; } - if (change) { - for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) - dvc->volume[i] = ucontrol->value.integer.value[i]; - + if (change) rsnd_dvc_volume_update(mod); - } return change; } -static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, - struct rsnd_dai *rdai, - struct snd_soc_pcm_runtime *rtd) +static int __rsnd_dvc_pcm_new(struct rsnd_mod *mod, + struct rsnd_dai *rdai, + struct snd_soc_pcm_runtime *rtd, + const unsigned char *name, + u8 *private) { - struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); struct snd_card *card = rtd->card->snd_card; struct snd_kcontrol *kctrl; - static struct snd_kcontrol_new knew = { + struct snd_kcontrol_new knew = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = name, .info = rsnd_dvc_volume_info, .get = rsnd_dvc_volume_get, .put = rsnd_dvc_volume_put, + .private_value = (unsigned long)private, }; int ret; - if (rsnd_dai_is_play(rdai, io)) - knew.name = "Playback Volume"; - else - knew.name = "Capture Volume"; - kctrl = snd_ctl_new1(&knew, mod); if (!kctrl) return -ENOMEM; @@ -217,6 +207,25 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, return 0; } +static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, + struct rsnd_dai *rdai, + struct snd_soc_pcm_runtime *rtd) +{ + struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); + struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + int ret; + + /* Volume */ + ret = __rsnd_dvc_pcm_new(mod, rdai, rtd, + rsnd_dai_is_play(rdai, io) ? + "DVC Out Playback Volume" : "DVC In Capture Volume", + dvc->volume); + if (ret < 0) + return ret; + + return 0; +} + static struct rsnd_mod_ops rsnd_dvc_ops = { .name = DVC_NAME, .probe = rsnd_dvc_probe_gen2, -- cgit v1.2.3 From cd2b65741e72da64508957cd1cde85116102d8dd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 1 Aug 2014 03:10:55 -0700 Subject: ASoC: rsnd: enable Mute control on DVC DVC can control Mute. This patch supports it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dvc.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 12a0a2068d34..3f443930c2b1 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -21,6 +21,7 @@ struct rsnd_dvc { struct rsnd_mod mod; struct clk *clk; u8 volume[RSND_DVC_VOLUME_NUM]; + u8 mute[RSND_DVC_VOLUME_NUM]; }; #define rsnd_mod_to_dvc(_mod) \ @@ -37,13 +38,18 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod) struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); u32 max = (0x00800000 - 1); u32 vol[RSND_DVC_VOLUME_NUM]; + u32 mute = 0; int i; - for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) + for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) { vol[i] = max / RSND_DVC_VOLUME_MAX * dvc->volume[i]; + mute |= (!!dvc->mute[i]) << i; + } rsnd_mod_write(mod, DVC_VOL0R, vol[0]); rsnd_mod_write(mod, DVC_VOL1R, vol[1]); + + rsnd_mod_write(mod, DVC_ZCMCR, mute); } static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod, @@ -96,8 +102,8 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod, rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod)); - /* enable Volume */ - rsnd_mod_write(dvc_mod, DVC_DVUCR, 0x100); + /* enable Volume / Mute */ + rsnd_mod_write(dvc_mod, DVC_DVUCR, 0x101); /* ch0/ch1 Volume */ rsnd_dvc_volume_update(dvc_mod); @@ -140,10 +146,20 @@ static int rsnd_dvc_stop(struct rsnd_mod *mod, static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl, struct snd_ctl_elem_info *uinfo) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); + struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + u8 *val = (u8 *)kctrl->private_value; + uinfo->count = RSND_DVC_VOLUME_NUM; uinfo->value.integer.min = 0; - uinfo->value.integer.max = RSND_DVC_VOLUME_MAX; + + if (val == dvc->volume) { + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->value.integer.max = RSND_DVC_VOLUME_MAX; + } else { + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->value.integer.max = 1; + } return 0; } @@ -223,6 +239,14 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, if (ret < 0) return ret; + /* Mute */ + ret = __rsnd_dvc_pcm_new(mod, rdai, rtd, + rsnd_dai_is_play(rdai, io) ? + "DVC Out Mute Switch" : "DVC In Mute Switch", + dvc->mute); + if (ret < 0) + return ret; + return 0; } -- cgit v1.2.3