Skip to content

Commit

Permalink
ASoC: sh: fsi: enable chip specific data transfer mode
Browse files Browse the repository at this point in the history
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 <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
  • Loading branch information
Kuninori Morimoto authored and Mark Brown committed May 19, 2012
1 parent f33238e commit 766812e
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 35 deletions.
6 changes: 5 additions & 1 deletion include/sound/sh_fsi.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@
/*
* flags format
*
* 0x000000BA
* 0x00000CBA
*
* A: inversion
* B: format mode
* C: chip specific
*/

/* A: clock inversion */
Expand All @@ -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
Expand Down
177 changes: 143 additions & 34 deletions sound/soc/sh/fsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -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()
*/
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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,
};
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;

Expand All @@ -1189,26 +1299,25 @@ 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);
fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD);
}

/*
* 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);
Expand Down Expand Up @@ -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;

Expand Down

0 comments on commit 766812e

Please sign in to comment.