diff options
-rw-r--r-- | include/sound/sh_fsi.h | 6 | ||||
-rw-r--r-- | sound/soc/sh/fsi.c | 177 |
2 files changed, 148 insertions, 35 deletions
diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h index 956e30e..9060103 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 e52a95d..7cee225 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -132,6 +132,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 * * xxx_num : number of data @@ -189,6 +208,11 @@ struct fsi_stream { int oerr_num; /* + * bus options + */ + u32 bus_option; + + /* * thse are initialized by fsi_handler_init() */ struct fsi_stream_handler *handler; @@ -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); @@ -584,6 +610,53 @@ static int fsi_stream_remove(struct fsi_priv *fsi) } /* + * 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; |