From 4d62ec125be98f5a446444e4ce53f4f4e2e1baff Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 May 2012 17:33:49 -0700 Subject: ASoC: sh: fsi: use register field macro name on IN/OUT_DMAC Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/sh/fsi.c') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 74ed2dffbffd..976a57ecc5be 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1217,8 +1217,8 @@ static int fsi_hw_startup(struct fsi_priv *fsi, * FSI2 chip can select it. */ if (fsi_ver >= 2) { - fsi_reg_write(fsi, OUT_DMAC, (1 << 4)); - fsi_reg_write(fsi, IN_DMAC, (1 << 4)); + fsi_reg_write(fsi, OUT_DMAC, VDMD_BACK); + fsi_reg_write(fsi, IN_DMAC, VDMD_BACK); } /* irq clear */ -- cgit v1.2.3 From 284c6f6547dd08d8f26e12f4014ec298faa7da03 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 May 2012 17:34:16 -0700 Subject: ASoC: sh: fsi: add fsi_version() and removed meaningless version check This patch adds fsi_version() function for accessing version. And there were some meaningless version check which never hit. This patch removed it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) (limited to 'sound/soc/sh/fsi.c') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 976a57ecc5be..6efe6c9a41f6 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -321,6 +321,10 @@ static void _fsi_master_mask_set(struct fsi_master *master, /* * basic function */ +static int fsi_version(struct fsi_master *master) +{ + return master->core->ver; +} static struct fsi_master *fsi_get_master(struct fsi_priv *fsi) { @@ -629,11 +633,6 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) struct fsi_master *master = fsi_get_master(fsi); u32 mask, val; - if (master->core->ver < 2) { - pr_err("fsi: register access err (%s)\n", __func__); - return; - } - mask = BP | SE; val = enable ? mask : 0; @@ -648,9 +647,7 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, long rate, int enable) { - struct fsi_master *master = fsi_get_master(fsi); set_rate_func set_rate = fsi_get_info_set_rate(fsi); - int fsi_ver = master->core->ver; int ret; if (!set_rate) @@ -682,10 +679,7 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, data |= (0x3 << 12); break; case SH_FSI_ACKMD_32: - if (fsi_ver < 2) - dev_err(dev, "unsupported ACKMD\n"); - else - data |= (0x4 << 12); + data |= (0x4 << 12); break; } @@ -708,10 +702,7 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, data |= (0x4 << 8); break; case SH_FSI_BPFMD_16: - if (fsi_ver < 2) - dev_err(dev, "unsupported ACKMD\n"); - else - data |= (0x7 << 8); + data |= (0x7 << 8); break; } @@ -1177,7 +1168,6 @@ static int fsi_hw_startup(struct fsi_priv *fsi, struct device *dev) { struct fsi_master *master = fsi_get_master(fsi); - int fsi_ver = master->core->ver; u32 flags = fsi_get_info_flags(fsi); u32 data = 0; @@ -1216,7 +1206,7 @@ static int fsi_hw_startup(struct fsi_priv *fsi, * FSI driver assumed that data package is in-back. * FSI2 chip can select it. */ - if (fsi_ver >= 2) { + if (fsi_version(master) >= 2) { fsi_reg_write(fsi, OUT_DMAC, VDMD_BACK); fsi_reg_write(fsi, IN_DMAC, VDMD_BACK); } @@ -1306,7 +1296,7 @@ static int fsi_set_fmt_spdif(struct fsi_priv *fsi) struct fsi_master *master = fsi_get_master(fsi); u32 data = 0; - if (master->core->ver < 2) + if (fsi_version(master) < 2) return -EINVAL; data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM; -- cgit v1.2.3 From 9c59dd342e4dd3c0bab5a9cad1aca7ed9501cbf8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 May 2012 17:34:53 -0700 Subject: ASoC: sh: fsi: use same format for IN/OUT Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) (limited to 'sound/soc/sh/fsi.c') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 6efe6c9a41f6..bddc353254ac 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -211,8 +211,7 @@ struct fsi_priv { struct fsi_stream playback; struct fsi_stream capture; - u32 do_fmt; - u32 di_fmt; + u32 fmt; int chan_num:16; int clk_master:1; @@ -1191,8 +1190,8 @@ static int fsi_hw_startup(struct fsi_priv *fsi, fsi_reg_write(fsi, CKG2, data); /* set format */ - fsi_reg_write(fsi, DO_FMT, fsi->do_fmt); - fsi_reg_write(fsi, DI_FMT, fsi->di_fmt); + fsi_reg_write(fsi, DO_FMT, fsi->fmt); + fsi_reg_write(fsi, DI_FMT, fsi->fmt); /* spdif ? */ if (fsi_is_spdif(fsi)) { @@ -1270,42 +1269,33 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt) { - u32 data = 0; - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: - data = CR_I2S; + fsi->fmt = CR_I2S; fsi->chan_num = 2; break; case SND_SOC_DAIFMT_LEFT_J: - data = CR_PCM; + fsi->fmt = CR_PCM; fsi->chan_num = 2; break; default: return -EINVAL; } - fsi->do_fmt = data; - fsi->di_fmt = data; - return 0; } static int fsi_set_fmt_spdif(struct fsi_priv *fsi) { struct fsi_master *master = fsi_get_master(fsi); - u32 data = 0; if (fsi_version(master) < 2) return -EINVAL; - data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM; + fsi->fmt = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM; fsi->chan_num = 2; fsi->spdif = 1; - fsi->do_fmt = data; - fsi->di_fmt = data; - return 0; } -- cgit v1.2.3 From f33238e96f619d9888713c07dcd92e4518879282 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 May 2012 17:35:34 -0700 Subject: ASoC: sh: fsi: call fsi_hw_startup/shutdown from fsi_dai_trigger() fsi_hw_startup/shutdown() needs the setup of bus width, but it is impossible to get parameter of snd_pcm_runtime at this timing. So, these functions are changed so that be called from fsi_dai_trigger(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'sound/soc/sh/fsi.c') diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index bddc353254ac..e52a95d44a6b 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1232,7 +1232,9 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, { struct fsi_priv *fsi = fsi_get_priv(substream); - return fsi_hw_startup(fsi, fsi_stream_get(fsi, substream), dai->dev); + fsi->rate = 0; + + return 0; } static void fsi_dai_shutdown(struct snd_pcm_substream *substream, @@ -1240,7 +1242,6 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream, { struct fsi_priv *fsi = fsi_get_priv(substream); - fsi_hw_shutdown(fsi, dai->dev); fsi->rate = 0; } @@ -1254,11 +1255,13 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_START: fsi_stream_init(fsi, io, substream); + fsi_hw_startup(fsi, io, dai->dev); ret = fsi_stream_transfer(io); if (0 == ret) fsi_stream_start(fsi, io); break; case SNDRV_PCM_TRIGGER_STOP: + fsi_hw_shutdown(fsi, dai->dev); fsi_stream_stop(fsi, io); fsi_stream_quit(fsi, io); break; -- cgit v1.2.3 From 766812e6d5e2e23be1e212cf84902d5e834dd865 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 May 2012 17:36:47 -0700 Subject: ASoC: sh: fsi: enable chip specific data transfer mode SupherH FSI2 can use special data transfer, but it depends on CPU-FSI2 connection style. We can use 16bit data stream mode if it was valid connection, and it is required for 16bit data DMA transfer / SPDIF sound output. We can use 24bit data transfer if it was invalid connection. We can select connection type if CPU is SH7372, and it is always valid connection if latest SuperH. This patch adds new bus_option and fsi_bus_setup() for supporting these feature. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/sh_fsi.h | 6 +- sound/soc/sh/fsi.c | 177 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 148 insertions(+), 35 deletions(-) (limited to 'sound/soc/sh/fsi.c') diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h index 956e30e89ea8..906010344dd7 100644 --- a/include/sound/sh_fsi.h +++ b/include/sound/sh_fsi.h @@ -21,10 +21,11 @@ /* * flags format * - * 0x000000BA + * 0x00000CBA * * A: inversion * B: format mode + * C: chip specific */ /* A: clock inversion */ @@ -39,6 +40,9 @@ #define SH_FSI_FMT_DAI (0 << 4) #define SH_FSI_FMT_SPDIF (1 << 4) +/* C: chip specific */ +#define SH_FSI_OPTION_MASK 0x00000F00 +#define SH_FSI_ENABLE_STREAM_MODE (1 << 8) /* for 16bit data */ /* * set_rate return value diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index e52a95d44a6b..7cee22515d9d 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -131,6 +131,25 @@ typedef int (*set_rate_func)(struct device *dev, int rate, int enable); +/* + * bus options + * + * 0x000000BA + * + * A : sample widtht 16bit setting + * B : sample widtht 24bit setting + */ + +#define SHIFT_16DATA 0 +#define SHIFT_24DATA 4 + +#define PACKAGE_24BITBUS_BACK 0 +#define PACKAGE_24BITBUS_FRONT 1 +#define PACKAGE_16BITBUS_STREAM 2 + +#define BUSOP_SET(s, a) ((a) << SHIFT_ ## s ## DATA) +#define BUSOP_GET(s, a) (((a) >> SHIFT_ ## s ## DATA) & 0xF) + /* * FSI driver use below type name for variable * @@ -188,6 +207,11 @@ struct fsi_stream { int uerr_num; int oerr_num; + /* + * bus options + */ + u32 bus_option; + /* * thse are initialized by fsi_handler_init() */ @@ -498,6 +522,7 @@ static void fsi_stream_init(struct fsi_priv *fsi, io->period_samples = fsi_frame2sample(fsi, runtime->period_size); io->period_pos = 0; io->sample_width = samples_to_bytes(runtime, 1); + io->bus_option = 0; io->oerr_num = -1; /* ignore 1st err */ io->uerr_num = -1; /* ignore 1st err */ fsi_stream_handler_call(io, init, fsi, io); @@ -525,6 +550,7 @@ static void fsi_stream_quit(struct fsi_priv *fsi, struct fsi_stream *io) io->period_samples = 0; io->period_pos = 0; io->sample_width = 0; + io->bus_option = 0; io->oerr_num = 0; io->uerr_num = 0; spin_unlock_irqrestore(&master->lock, flags); @@ -583,6 +609,53 @@ static int fsi_stream_remove(struct fsi_priv *fsi) return 0; } +/* + * format/bus/dma setting + */ +static void fsi_format_bus_setup(struct fsi_priv *fsi, struct fsi_stream *io, + u32 bus, struct device *dev) +{ + struct fsi_master *master = fsi_get_master(fsi); + int is_play = fsi_stream_is_play(fsi, io); + u32 fmt = fsi->fmt; + + if (fsi_version(master) >= 2) { + u32 dma = 0; + + /* + * FSI2 needs DMA/Bus setting + */ + switch (bus) { + case PACKAGE_24BITBUS_FRONT: + fmt |= CR_BWS_24; + dma |= VDMD_FRONT; + dev_dbg(dev, "24bit bus / package in front\n"); + break; + case PACKAGE_16BITBUS_STREAM: + fmt |= CR_BWS_16; + dma |= VDMD_STREAM; + dev_dbg(dev, "16bit bus / stream mode\n"); + break; + case PACKAGE_24BITBUS_BACK: + default: + fmt |= CR_BWS_24; + dma |= VDMD_BACK; + dev_dbg(dev, "24bit bus / package in back\n"); + break; + } + + if (is_play) + fsi_reg_write(fsi, OUT_DMAC, dma); + else + fsi_reg_write(fsi, IN_DMAC, dma); + } + + if (is_play) + fsi_reg_write(fsi, DO_FMT, fmt); + else + fsi_reg_write(fsi, DI_FMT, fmt); +} + /* * irq function */ @@ -718,11 +791,26 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, */ static void fsi_pio_push16(struct fsi_priv *fsi, u8 *_buf, int samples) { - u16 *buf = (u16 *)_buf; + u32 enable_stream = fsi_get_info_flags(fsi) & SH_FSI_ENABLE_STREAM_MODE; int i; - for (i = 0; i < samples; i++) - fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8)); + if (enable_stream) { + /* + * stream mode + * see + * fsi_pio_push_init() + */ + u32 *buf = (u32 *)_buf; + + for (i = 0; i < samples / 2; i++) + fsi_reg_write(fsi, DODT, buf[i]); + } else { + /* normal mode */ + u16 *buf = (u16 *)_buf; + + for (i = 0; i < samples; i++) + fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8)); + } } static void fsi_pio_pop16(struct fsi_priv *fsi, u8 *_buf, int samples) @@ -862,12 +950,44 @@ static void fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); } +static int fsi_pio_push_init(struct fsi_priv *fsi, struct fsi_stream *io) +{ + u32 enable_stream = fsi_get_info_flags(fsi) & SH_FSI_ENABLE_STREAM_MODE; + + /* + * we can use 16bit stream mode + * when "playback" and "16bit data" + * and platform allows "stream mode" + * see + * fsi_pio_push16() + */ + if (enable_stream) + io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | + BUSOP_SET(16, PACKAGE_16BITBUS_STREAM); + else + io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | + BUSOP_SET(16, PACKAGE_24BITBUS_BACK); + return 0; +} + +static int fsi_pio_pop_init(struct fsi_priv *fsi, struct fsi_stream *io) +{ + /* + * always 24bit bus, package back when "capture" + */ + io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | + BUSOP_SET(16, PACKAGE_24BITBUS_BACK); + return 0; +} + static struct fsi_stream_handler fsi_pio_push_handler = { + .init = fsi_pio_push_init, .transfer = fsi_pio_push, .start_stop = fsi_pio_start_stop, }; static struct fsi_stream_handler fsi_pio_pop_handler = { + .init = fsi_pio_pop_init, .transfer = fsi_pio_pop, .start_stop = fsi_pio_start_stop, }; @@ -909,6 +1029,13 @@ static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io) 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 + */ + io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | + BUSOP_SET(16, PACKAGE_16BITBUS_STREAM); + io->dma = dma_map_single(dai->dev, runtime->dma_area, snd_pcm_lib_buffer_bytes(io->substream), dir); return 0; @@ -1045,25 +1172,9 @@ static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, int start) { - u32 bws; - u32 dma; + u32 enable = start ? DMA_ON : 0; - switch (io->sample_width * start) { - case 2: - bws = CR_BWS_16; - dma = VDMD_STREAM | DMA_ON; - break; - case 4: - bws = CR_BWS_24; - dma = VDMD_BACK | DMA_ON; - break; - default: - bws = 0; - dma = 0; - } - - fsi_reg_mask_set(fsi, DO_FMT, CR_BWS_MASK, bws); - fsi_reg_write(fsi, OUT_DMAC, dma); + fsi_reg_mask_set(fsi, OUT_DMAC, DMA_ON, enable); } static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io) @@ -1166,7 +1277,6 @@ static int fsi_hw_startup(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev) { - struct fsi_master *master = fsi_get_master(fsi); u32 flags = fsi_get_info_flags(fsi); u32 data = 0; @@ -1189,10 +1299,6 @@ static int fsi_hw_startup(struct fsi_priv *fsi, fsi_reg_write(fsi, CKG2, data); - /* set format */ - fsi_reg_write(fsi, DO_FMT, fsi->fmt); - fsi_reg_write(fsi, DI_FMT, fsi->fmt); - /* spdif ? */ if (fsi_is_spdif(fsi)) { fsi_spdif_clk_ctrl(fsi, 1); @@ -1200,15 +1306,18 @@ static int fsi_hw_startup(struct fsi_priv *fsi, } /* - * FIXME - * - * FSI driver assumed that data package is in-back. - * FSI2 chip can select it. + * get bus settings */ - if (fsi_version(master) >= 2) { - fsi_reg_write(fsi, OUT_DMAC, VDMD_BACK); - fsi_reg_write(fsi, IN_DMAC, VDMD_BACK); + data = 0; + switch (io->sample_width) { + case 2: + data = BUSOP_GET(16, io->bus_option); + break; + case 4: + data = BUSOP_GET(24, io->bus_option); + break; } + fsi_format_bus_setup(fsi, io, data, dev); /* irq clear */ fsi_irq_disable(fsi, io); @@ -1295,7 +1404,7 @@ static int fsi_set_fmt_spdif(struct fsi_priv *fsi) if (fsi_version(master) < 2) return -EINVAL; - fsi->fmt = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM; + fsi->fmt = CR_DTMD_SPDIF_PCM | CR_PCM; fsi->chan_num = 2; fsi->spdif = 1; -- cgit v1.2.3