提交 2fd53734 编写于 作者: M Mark Brown

Merge remote-tracking branch 'asoc/topic/rcar' into asoc-next

...@@ -13,6 +13,9 @@ Required properties: ...@@ -13,6 +13,9 @@ Required properties:
- rcar_sound,src : Should contain SRC feature. - rcar_sound,src : Should contain SRC feature.
The number of SRC subnode should be same as HW. The number of SRC subnode should be same as HW.
see below for detail. see below for detail.
- rcar_sound,dvc : Should contain DVC feature.
The number of DVC subnode should be same as HW.
see below for detail.
- rcar_sound,dai : DAI contents. - rcar_sound,dai : DAI contents.
The number of DAI subnode should be same as HW. The number of DAI subnode should be same as HW.
see below for detail. see below for detail.
...@@ -21,6 +24,7 @@ SSI subnode properties: ...@@ -21,6 +24,7 @@ SSI subnode properties:
- interrupts : Should contain SSI interrupt for PIO transfer - interrupts : Should contain SSI interrupt for PIO transfer
- shared-pin : if shared clock pin - shared-pin : if shared clock pin
- pio-transfer : use PIO transfer mode - pio-transfer : use PIO transfer mode
- no-busif : BUSIF is not ussed when [mem -> SSI] via DMA case
SRC subnode properties: SRC subnode properties:
no properties at this point no properties at this point
...@@ -39,6 +43,11 @@ rcar_sound: rcar_sound@0xffd90000 { ...@@ -39,6 +43,11 @@ rcar_sound: rcar_sound@0xffd90000 {
<0 0xec540000 0 0x1000>, /* SSIU */ <0 0xec540000 0 0x1000>, /* SSIU */
<0 0xec541000 0 0x1280>; /* SSI */ <0 0xec541000 0 0x1280>; /* SSI */
rcar_sound,dvc {
dvc0: dvc@0 { };
dvc1: dvc@1 { };
};
rcar_sound,src { rcar_sound,src {
src0: src@0 { }; src0: src@0 { };
src1: src@1 { }; src1: src@1 { };
......
...@@ -998,6 +998,8 @@ static struct platform_device fsi_wm8978_device = { ...@@ -998,6 +998,8 @@ static struct platform_device fsi_wm8978_device = {
.id = 0, .id = 0,
.dev = { .dev = {
.platform_data = &fsi_wm8978_info, .platform_data = &fsi_wm8978_info,
.coherent_dma_mask = DMA_BIT_MASK(32),
.dma_mask = &fsi_wm8978_device.dev.coherent_dma_mask,
}, },
}; };
...@@ -1021,6 +1023,8 @@ static struct platform_device fsi_hdmi_device = { ...@@ -1021,6 +1023,8 @@ static struct platform_device fsi_hdmi_device = {
.id = 1, .id = 1,
.dev = { .dev = {
.platform_data = &fsi2_hdmi_info, .platform_data = &fsi2_hdmi_info,
.coherent_dma_mask = DMA_BIT_MASK(32),
.dma_mask = &fsi_hdmi_device.dev.coherent_dma_mask,
}, },
}; };
......
...@@ -603,6 +603,8 @@ static struct platform_device fsi_ak4648_device = { ...@@ -603,6 +603,8 @@ static struct platform_device fsi_ak4648_device = {
.name = "asoc-simple-card", .name = "asoc-simple-card",
.dev = { .dev = {
.platform_data = &fsi2_ak4648_info, .platform_data = &fsi2_ak4648_info,
.coherent_dma_mask = DMA_BIT_MASK(32),
.dma_mask = &fsi_ak4648_device.dev.coherent_dma_mask,
}, },
}; };
......
...@@ -523,6 +523,8 @@ static struct platform_device fsi_hdmi_device = { ...@@ -523,6 +523,8 @@ static struct platform_device fsi_hdmi_device = {
.id = 1, .id = 1,
.dev = { .dev = {
.platform_data = &fsi2_hdmi_info, .platform_data = &fsi2_hdmi_info,
.coherent_dma_mask = DMA_BIT_MASK(32),
.dma_mask = &fsi_hdmi_device.dev.coherent_dma_mask,
}, },
}; };
...@@ -919,6 +921,8 @@ static struct platform_device fsi_ak4643_device = { ...@@ -919,6 +921,8 @@ static struct platform_device fsi_ak4643_device = {
.name = "asoc-simple-card", .name = "asoc-simple-card",
.dev = { .dev = {
.platform_data = &fsi2_ak4643_info, .platform_data = &fsi2_ak4643_info,
.coherent_dma_mask = DMA_BIT_MASK(32),
.dma_mask = &fsi_ak4643_device.dev.coherent_dma_mask,
}, },
}; };
......
...@@ -874,6 +874,8 @@ static struct platform_device fsi_da7210_device = { ...@@ -874,6 +874,8 @@ static struct platform_device fsi_da7210_device = {
.name = "asoc-simple-card", .name = "asoc-simple-card",
.dev = { .dev = {
.platform_data = &fsi_da7210_info, .platform_data = &fsi_da7210_info,
.coherent_dma_mask = DMA_BIT_MASK(32),
.dma_mask = &fsi_da7210_device.dev.coherent_dma_mask,
}, },
}; };
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
* B : SSI direction * B : SSI direction
*/ */
#define RSND_SSI_CLK_PIN_SHARE (1 << 31) #define RSND_SSI_CLK_PIN_SHARE (1 << 31)
#define RSND_SSI_NO_BUSIF (1 << 30) /* SSI+DMA without BUSIF */
#define RSND_SSI(_dma_id, _pio_irq, _flags) \ #define RSND_SSI(_dma_id, _pio_irq, _flags) \
{ .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags } { .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags }
......
...@@ -37,7 +37,7 @@ config SND_SOC_SH4_SIU ...@@ -37,7 +37,7 @@ config SND_SOC_SH4_SIU
config SND_SOC_RCAR config SND_SOC_RCAR
tristate "R-Car series SRU/SCU/SSIU/SSI support" tristate "R-Car series SRU/SCU/SSIU/SSI support"
select SND_SIMPLE_CARD select SND_SIMPLE_CARD
select REGMAP select REGMAP_MMIO
help help
This option enables R-Car SUR/SCU/SSIU/SSI sound support This option enables R-Car SUR/SCU/SSIU/SSI sound support
......
...@@ -232,11 +232,7 @@ struct fsi_stream { ...@@ -232,11 +232,7 @@ struct fsi_stream {
* these are for DMAEngine * these are for DMAEngine
*/ */
struct dma_chan *chan; struct dma_chan *chan;
struct work_struct work;
dma_addr_t dma;
int dma_id; int dma_id;
int loop_cnt;
int additional_pos;
}; };
struct fsi_clk { struct fsi_clk {
...@@ -1042,6 +1038,26 @@ static int fsi_clk_set_rate_cpg(struct device *dev, ...@@ -1042,6 +1038,26 @@ static int fsi_clk_set_rate_cpg(struct device *dev,
return ret; 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 * pio data transfer handler
*/ */
...@@ -1108,31 +1124,11 @@ static int fsi_pio_transfer(struct fsi_priv *fsi, struct fsi_stream *io, ...@@ -1108,31 +1124,11 @@ static int fsi_pio_transfer(struct fsi_priv *fsi, struct fsi_stream *io,
void (*run32)(struct fsi_priv *fsi, u8 *buf, int samples), void (*run32)(struct fsi_priv *fsi, u8 *buf, int samples),
int samples) int samples)
{ {
struct snd_pcm_runtime *runtime;
struct snd_pcm_substream *substream;
u8 *buf; u8 *buf;
int over_period;
if (!fsi_stream_is_working(fsi, io)) if (!fsi_stream_is_working(fsi, io))
return -EINVAL; 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); buf = fsi_pio_get_area(fsi, io);
switch (io->sample_width) { switch (io->sample_width) {
...@@ -1146,11 +1142,7 @@ static int fsi_pio_transfer(struct fsi_priv *fsi, struct fsi_stream *io, ...@@ -1146,11 +1142,7 @@ static int fsi_pio_transfer(struct fsi_priv *fsi, struct fsi_stream *io,
return -EINVAL; return -EINVAL;
} }
/* update buff_sample_pos */ fsi_pointer_update(io, samples);
io->buff_sample_pos += samples;
if (over_period)
snd_pcm_period_elapsed(substream);
return 0; return 0;
} }
...@@ -1279,11 +1271,6 @@ static irqreturn_t fsi_interrupt(int irq, void *data) ...@@ -1279,11 +1271,6 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
*/ */
static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io) 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 * 24bit data : 24bit bus / package in back
* 16bit data : 16bit bus / stream mode * 16bit data : 16bit bus / stream mode
...@@ -1291,91 +1278,37 @@ static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io) ...@@ -1291,91 +1278,37 @@ static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io)
io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
BUSOP_SET(16, PACKAGE_16BITBUS_STREAM); BUSOP_SET(16, PACKAGE_16BITBUS_STREAM);
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; 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 io->dma + samples_to_bytes(runtime, period * io->period_samples);
}
static void fsi_dma_complete(void *data) static void fsi_dma_complete(void *data)
{ {
struct fsi_stream *io = (struct fsi_stream *)data; struct fsi_stream *io = (struct fsi_stream *)data;
struct fsi_priv *fsi = fsi_stream_to_priv(io); 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), fsi_pointer_update(io, io->period_samples);
samples_to_bytes(runtime, io->period_samples), dir);
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_count_fifo_err(fsi); 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) 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 snd_soc_dai *dai = fsi_get_dai(io->substream);
struct fsi_priv *fsi = fsi_stream_to_priv(io); struct snd_pcm_substream *substream = io->substream;
struct snd_soc_dai *dai;
struct dma_async_tx_descriptor *desc; 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 is_play = fsi_stream_is_play(fsi, io);
int len, i; enum dma_data_direction dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
dma_addr_t buf; int ret = -EIO;
if (!fsi_stream_is_working(fsi, io)) desc = dmaengine_prep_dma_cyclic(io->chan,
return; substream->runtime->dma_addr,
snd_pcm_lib_buffer_bytes(substream),
dai = fsi_get_dai(io->substream); snd_pcm_lib_period_bytes(substream),
runtime = io->substream->runtime; dir,
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);
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); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) { if (!desc) {
dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n"); dev_err(dai->dev, "dmaengine_prep_dma_cyclic() fail\n");
return; goto fsi_dma_transfer_err;
} }
desc->callback = fsi_dma_complete; desc->callback = fsi_dma_complete;
...@@ -1383,16 +1316,11 @@ static void fsi_dma_do_work(struct work_struct *work) ...@@ -1383,16 +1316,11 @@ static void fsi_dma_do_work(struct work_struct *work)
if (dmaengine_submit(desc) < 0) { if (dmaengine_submit(desc) < 0) {
dev_err(dai->dev, "tx_submit() fail\n"); dev_err(dai->dev, "tx_submit() fail\n");
return; goto fsi_dma_transfer_err;
} }
dma_async_issue_pending(io->chan); dma_async_issue_pending(io->chan);
io->additional_pos = 1;
}
io->loop_cnt = 1;
/* /*
* FIXME * FIXME
* *
...@@ -1408,13 +1336,11 @@ static void fsi_dma_do_work(struct work_struct *work) ...@@ -1408,13 +1336,11 @@ static void fsi_dma_do_work(struct work_struct *work)
fsi_reg_write(fsi, DIFF_ST, 0); fsi_reg_write(fsi, DIFF_ST, 0);
} }
} }
}
static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) ret = 0;
{
schedule_work(&io->work);
return 0; fsi_dma_transfer_err:
return ret;
} }
static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
...@@ -1475,15 +1401,11 @@ static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct dev ...@@ -1475,15 +1401,11 @@ static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct dev
return fsi_stream_probe(fsi, dev); return fsi_stream_probe(fsi, dev);
} }
INIT_WORK(&io->work, fsi_dma_do_work);
return 0; return 0;
} }
static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io) static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io)
{ {
cancel_work_sync(&io->work);
fsi_stream_stop(fsi, io); fsi_stream_stop(fsi, io);
if (io->chan) if (io->chan)
...@@ -1495,7 +1417,6 @@ static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io) ...@@ -1495,7 +1417,6 @@ static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io)
static struct fsi_stream_handler fsi_dma_push_handler = { static struct fsi_stream_handler fsi_dma_push_handler = {
.init = fsi_dma_init, .init = fsi_dma_init,
.quit = fsi_dma_quit,
.probe = fsi_dma_probe, .probe = fsi_dma_probe,
.transfer = fsi_dma_transfer, .transfer = fsi_dma_transfer,
.remove = fsi_dma_remove, .remove = fsi_dma_remove,
...@@ -1657,9 +1578,9 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -1657,9 +1578,9 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
if (!ret) if (!ret)
ret = fsi_hw_startup(fsi, io, dai->dev); ret = fsi_hw_startup(fsi, io, dai->dev);
if (!ret) if (!ret)
ret = fsi_stream_transfer(io); ret = fsi_stream_start(fsi, io);
if (!ret) if (!ret)
fsi_stream_start(fsi, io); ret = fsi_stream_transfer(io);
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
if (!ret) if (!ret)
...@@ -1850,16 +1771,10 @@ static void fsi_pcm_free(struct snd_pcm *pcm) ...@@ -1850,16 +1771,10 @@ static void fsi_pcm_free(struct snd_pcm *pcm)
static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd) 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( return snd_pcm_lib_preallocate_pages_for_all(
pcm, rtd->pcm,
SNDRV_DMA_TYPE_CONTINUOUS, SNDRV_DMA_TYPE_DEV,
snd_dma_continuous_data(GFP_KERNEL), rtd->card->snd_card->dev,
PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
} }
......
...@@ -138,6 +138,17 @@ char *rsnd_mod_name(struct rsnd_mod *mod) ...@@ -138,6 +138,17 @@ char *rsnd_mod_name(struct rsnd_mod *mod)
return mod->ops->name; 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, void rsnd_mod_init(struct rsnd_priv *priv,
struct rsnd_mod *mod, struct rsnd_mod *mod,
struct rsnd_mod_ops *ops, struct rsnd_mod_ops *ops,
...@@ -153,26 +164,8 @@ void rsnd_mod_init(struct rsnd_priv *priv, ...@@ -153,26 +164,8 @@ void rsnd_mod_init(struct rsnd_priv *priv,
/* /*
* rsnd_dma functions * 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) void rsnd_dma_stop(struct rsnd_dma *dma)
{ {
dma->submit_loop = 0;
cancel_work_sync(&dma->work);
dmaengine_terminate_all(dma->chan); dmaengine_terminate_all(dma->chan);
} }
...@@ -180,11 +173,7 @@ static void rsnd_dma_complete(void *data) ...@@ -180,11 +173,7 @@ static void rsnd_dma_complete(void *data)
{ {
struct rsnd_dma *dma = (struct rsnd_dma *)data; struct rsnd_dma *dma = (struct rsnd_dma *)data;
struct rsnd_mod *mod = rsnd_dma_to_mod(dma); 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); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
unsigned long flags;
rsnd_lock(priv, flags);
/* /*
* Renesas sound Gen1 needs 1 DMAC, * Renesas sound Gen1 needs 1 DMAC,
...@@ -197,35 +186,27 @@ static void rsnd_dma_complete(void *data) ...@@ -197,35 +186,27 @@ static void rsnd_dma_complete(void *data)
* rsnd_dai_pointer_update() will be called twice, * rsnd_dai_pointer_update() will be called twice,
* ant it will breaks io->byte_pos * 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); 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_mod *mod = rsnd_dma_to_mod(dma);
struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct rsnd_dai_stream *io = rsnd_mod_to_io(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 device *dev = rsnd_priv_to_dev(priv);
struct dma_async_tx_descriptor *desc; 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++) { desc = dmaengine_prep_dma_cyclic(dma->chan,
(dma->addr) ? dma->addr :
buf = runtime->dma_addr + substream->runtime->dma_addr,
rsnd_dai_pointer_offset(io, dma->offset + len); snd_pcm_lib_buffer_bytes(substream),
dma->offset = len; snd_pcm_lib_period_bytes(substream),
dma->dir,
desc = dmaengine_prep_slave_single(
dma->chan, buf, len, dma->dir,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) { if (!desc) {
dev_err(dev, "dmaengine_prep_slave_sg() fail\n"); dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
return; return;
...@@ -240,14 +221,6 @@ static void __rsnd_dma_start(struct rsnd_dma *dma) ...@@ -240,14 +221,6 @@ static void __rsnd_dma_start(struct rsnd_dma *dma)
} }
dma_async_issue_pending(dma->chan); dma_async_issue_pending(dma->chan);
}
}
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);
} }
int rsnd_dma_available(struct rsnd_dma *dma) int rsnd_dma_available(struct rsnd_dma *dma)
...@@ -261,14 +234,27 @@ static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod) ...@@ -261,14 +234,27 @@ static int _rsnd_dma_of_name(char *dma_name, struct rsnd_mod *mod)
{ {
if (mod) if (mod)
return snprintf(dma_name, DMA_NAME_SIZE / 2, "%s%d", 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 else
return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem"); return snprintf(dma_name, DMA_NAME_SIZE / 2, "mem");
} }
static void rsnd_dma_of_name(struct rsnd_dma *dma, static void rsnd_dma_of_name(struct rsnd_mod *mod_from,
int is_play, char *dma_name) 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_mod *this = rsnd_dma_to_mod(dma);
struct rsnd_dai_stream *io = rsnd_mod_to_io(this); struct rsnd_dai_stream *io = rsnd_mod_to_io(this);
...@@ -276,7 +262,6 @@ static void rsnd_dma_of_name(struct rsnd_dma *dma, ...@@ -276,7 +262,6 @@ static void rsnd_dma_of_name(struct rsnd_dma *dma,
struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct rsnd_mod *src = rsnd_io_to_mod_src(io);
struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
struct rsnd_mod *mod[MOD_MAX]; struct rsnd_mod *mod[MOD_MAX];
struct rsnd_mod *src_mod, *dst_mod;
int i, index; int i, index;
...@@ -301,7 +286,13 @@ static void rsnd_dma_of_name(struct rsnd_dma *dma, ...@@ -301,7 +286,13 @@ static void rsnd_dma_of_name(struct rsnd_dma *dma,
mod[i] = src; mod[i] = src;
src = NULL; src = NULL;
} else { } 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; dvc = NULL;
} }
...@@ -313,17 +304,12 @@ static void rsnd_dma_of_name(struct rsnd_dma *dma, ...@@ -313,17 +304,12 @@ static void rsnd_dma_of_name(struct rsnd_dma *dma,
} }
if (is_play) { if (is_play) {
src_mod = mod[index - 1]; *mod_from = mod[index - 1];
dst_mod = mod[index]; *mod_to = mod[index];
} else { } else {
src_mod = mod[index]; *mod_from = mod[index];
dst_mod = mod[index - 1]; *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, int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
...@@ -331,6 +317,8 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, ...@@ -331,6 +317,8 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
{ {
struct device *dev = rsnd_priv_to_dev(priv); struct device *dev = rsnd_priv_to_dev(priv);
struct dma_slave_config cfg; struct dma_slave_config cfg;
struct rsnd_mod *mod_from;
struct rsnd_mod *mod_to;
char dma_name[DMA_NAME_SIZE]; char dma_name[DMA_NAME_SIZE];
dma_cap_mask_t mask; dma_cap_mask_t mask;
int ret; int ret;
...@@ -343,13 +331,18 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, ...@@ -343,13 +331,18 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
dma_cap_zero(mask); dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask);
if (dev->of_node) rsnd_dma_of_path(dma, is_play, &mod_from, &mod_to);
rsnd_dma_of_name(dma, is_play, dma_name); rsnd_dma_of_name(mod_from, mod_to, dma_name);
else
snprintf(dma_name, DMA_NAME_SIZE,
is_play ? "tx" : "rx");
dev_dbg(dev, "dma name : %s\n", 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);
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);
dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
(void *)id, dev, (void *)id, dev,
...@@ -359,14 +352,12 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, ...@@ -359,14 +352,12 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
return -EIO; return -EIO;
} }
rsnd_gen_dma_addr(priv, dma, &cfg, is_play, id);
ret = dmaengine_slave_config(dma->chan, &cfg); ret = dmaengine_slave_config(dma->chan, &cfg);
if (ret < 0) if (ret < 0)
goto rsnd_dma_init_err; goto rsnd_dma_init_err;
dma->dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; dma->addr = is_play ? cfg.src_addr : cfg.dst_addr;
INIT_WORK(&dma->work, rsnd_dma_do_work); dma->dir = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
return 0; return 0;
...@@ -633,40 +624,41 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) ...@@ -633,40 +624,41 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL; 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 */ /* set format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_I2S:
rdai->sys_delay = 0; rdai->sys_delay = 0;
rdai->data_alignment = 0; rdai->data_alignment = 0;
rdai->frm_clk_inv = 0;
break; break;
case SND_SOC_DAIFMT_LEFT_J: case SND_SOC_DAIFMT_LEFT_J:
rdai->sys_delay = 1; rdai->sys_delay = 1;
rdai->data_alignment = 0; rdai->data_alignment = 0;
rdai->frm_clk_inv = 1;
break; break;
case SND_SOC_DAIFMT_RIGHT_J: case SND_SOC_DAIFMT_RIGHT_J:
rdai->sys_delay = 1; rdai->sys_delay = 1;
rdai->data_alignment = 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; break;
} }
...@@ -736,12 +728,13 @@ static void rsnd_of_parse_dai(struct platform_device *pdev, ...@@ -736,12 +728,13 @@ static void rsnd_of_parse_dai(struct platform_device *pdev,
struct device_node *dai_node, *dai_np; struct device_node *dai_node, *dai_np;
struct device_node *ssi_node, *ssi_np; struct device_node *ssi_node, *ssi_np;
struct device_node *src_node, *src_np; struct device_node *src_node, *src_np;
struct device_node *dvc_node, *dvc_np;
struct device_node *playback, *capture; struct device_node *playback, *capture;
struct rsnd_dai_platform_info *dai_info; struct rsnd_dai_platform_info *dai_info;
struct rcar_snd_info *info = rsnd_priv_to_info(priv); struct rcar_snd_info *info = rsnd_priv_to_info(priv);
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
int nr, i; int nr, i;
int dai_i, ssi_i, src_i; int dai_i, ssi_i, src_i, dvc_i;
if (!of_data) if (!of_data)
return; return;
...@@ -767,6 +760,7 @@ static void rsnd_of_parse_dai(struct platform_device *pdev, ...@@ -767,6 +760,7 @@ static void rsnd_of_parse_dai(struct platform_device *pdev,
ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi"); 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"); 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) \ #define mod_parse(name) \
if (name##_node) { \ if (name##_node) { \
...@@ -802,6 +796,7 @@ if (name##_node) { \ ...@@ -802,6 +796,7 @@ if (name##_node) { \
mod_parse(ssi); mod_parse(ssi);
mod_parse(src); mod_parse(src);
mod_parse(dvc);
if (playback) if (playback)
of_node_put(playback); of_node_put(playback);
...@@ -950,11 +945,10 @@ static struct snd_pcm_ops rsnd_pcm_ops = { ...@@ -950,11 +945,10 @@ static struct snd_pcm_ops rsnd_pcm_ops = {
static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd) static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
{ {
struct rsnd_priv *priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); struct snd_soc_dai *dai = rtd->cpu_dai;
struct rsnd_dai *rdai; struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
int i, ret; int ret;
for_each_rsnd_dai(rdai, priv, i) {
ret = rsnd_dai_call(pcm_new, &rdai->playback, rdai, rtd); ret = rsnd_dai_call(pcm_new, &rdai->playback, rdai, rtd);
if (ret) if (ret)
return ret; return ret;
...@@ -962,7 +956,6 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd) ...@@ -962,7 +956,6 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
ret = rsnd_dai_call(pcm_new, &rdai->capture, rdai, rtd); ret = rsnd_dai_call(pcm_new, &rdai->capture, rdai, rtd);
if (ret) if (ret)
return ret; return ret;
}
return snd_pcm_lib_preallocate_pages_for_all( return snd_pcm_lib_preallocate_pages_for_all(
rtd->pcm, rtd->pcm,
...@@ -1049,11 +1042,11 @@ static int rsnd_probe(struct platform_device *pdev) ...@@ -1049,11 +1042,11 @@ static int rsnd_probe(struct platform_device *pdev)
for_each_rsnd_dai(rdai, priv, i) { for_each_rsnd_dai(rdai, priv, i) {
ret = rsnd_dai_call(probe, &rdai->playback, rdai); ret = rsnd_dai_call(probe, &rdai->playback, rdai);
if (ret) if (ret)
return ret; goto exit_snd_probe;
ret = rsnd_dai_call(probe, &rdai->capture, rdai); ret = rsnd_dai_call(probe, &rdai->capture, rdai);
if (ret) if (ret)
return ret; goto exit_snd_probe;
} }
/* /*
...@@ -1081,6 +1074,11 @@ static int rsnd_probe(struct platform_device *pdev) ...@@ -1081,6 +1074,11 @@ static int rsnd_probe(struct platform_device *pdev)
exit_snd_soc: exit_snd_soc:
snd_soc_unregister_platform(dev); 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; return ret;
} }
...@@ -1089,21 +1087,16 @@ static int rsnd_remove(struct platform_device *pdev) ...@@ -1089,21 +1087,16 @@ static int rsnd_remove(struct platform_device *pdev)
{ {
struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev);
struct rsnd_dai *rdai; struct rsnd_dai *rdai;
int ret, i; int ret = 0, i;
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
for_each_rsnd_dai(rdai, priv, i) { for_each_rsnd_dai(rdai, priv, i) {
ret = rsnd_dai_call(remove, &rdai->playback, rdai); ret |= rsnd_dai_call(remove, &rdai->playback, rdai);
if (ret) ret |= rsnd_dai_call(remove, &rdai->capture, rdai);
return ret;
ret = rsnd_dai_call(remove, &rdai->capture, rdai);
if (ret)
return ret;
} }
return 0; return ret;
} }
static struct platform_driver rsnd_driver = { static struct platform_driver rsnd_driver = {
......
...@@ -20,7 +20,8 @@ struct rsnd_dvc { ...@@ -20,7 +20,8 @@ struct rsnd_dvc {
struct rsnd_dvc_platform_info *info; /* rcar_snd.h */ struct rsnd_dvc_platform_info *info; /* rcar_snd.h */
struct rsnd_mod mod; struct rsnd_mod mod;
struct clk *clk; struct clk *clk;
long volume[RSND_DVC_VOLUME_NUM]; u8 volume[RSND_DVC_VOLUME_NUM];
u8 mute[RSND_DVC_VOLUME_NUM];
}; };
#define rsnd_mod_to_dvc(_mod) \ #define rsnd_mod_to_dvc(_mod) \
...@@ -37,13 +38,18 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod) ...@@ -37,13 +38,18 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod)
struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
u32 max = (0x00800000 - 1); u32 max = (0x00800000 - 1);
u32 vol[RSND_DVC_VOLUME_NUM]; u32 vol[RSND_DVC_VOLUME_NUM];
u32 mute = 0;
int i; 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]; 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_VOL0R, vol[0]);
rsnd_mod_write(mod, DVC_VOL1R, vol[1]); 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, static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod,
...@@ -96,8 +102,8 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_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)); rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod));
/* enable Volume */ /* enable Volume / Mute */
rsnd_mod_write(dvc_mod, DVC_DVUCR, 0x100); rsnd_mod_write(dvc_mod, DVC_DVUCR, 0x101);
/* ch0/ch1 Volume */ /* ch0/ch1 Volume */
rsnd_dvc_volume_update(dvc_mod); rsnd_dvc_volume_update(dvc_mod);
...@@ -140,10 +146,20 @@ static int rsnd_dvc_stop(struct rsnd_mod *mod, ...@@ -140,10 +146,20 @@ static int rsnd_dvc_stop(struct rsnd_mod *mod,
static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl, static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_info *uinfo) 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->count = RSND_DVC_VOLUME_NUM;
uinfo->value.integer.min = 0; uinfo->value.integer.min = 0;
if (val == dvc->volume) {
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->value.integer.max = RSND_DVC_VOLUME_MAX; uinfo->value.integer.max = RSND_DVC_VOLUME_MAX;
} else {
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->value.integer.max = 1;
}
return 0; return 0;
} }
...@@ -151,12 +167,11 @@ static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl, ...@@ -151,12 +167,11 @@ static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl,
static int rsnd_dvc_volume_get(struct snd_kcontrol *kctrl, static int rsnd_dvc_volume_get(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); u8 *val = (u8 *)kctrl->private_value;
struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
int i; int i;
for (i = 0; i < RSND_DVC_VOLUME_NUM; 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; return 0;
} }
...@@ -165,51 +180,38 @@ static int rsnd_dvc_volume_put(struct snd_kcontrol *kctrl, ...@@ -165,51 +180,38 @@ static int rsnd_dvc_volume_put(struct snd_kcontrol *kctrl,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); 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; int i, change = 0;
for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) { for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) {
if (ucontrol->value.integer.value[i] < 0 || change |= (ucontrol->value.integer.value[i] != val[i]);
ucontrol->value.integer.value[i] > RSND_DVC_VOLUME_MAX) val[i] = ucontrol->value.integer.value[i];
return -EINVAL;
change |= (ucontrol->value.integer.value[i] != dvc->volume[i]);
} }
if (change) { if (change)
for (i = 0; i < RSND_DVC_VOLUME_NUM; i++)
dvc->volume[i] = ucontrol->value.integer.value[i];
rsnd_dvc_volume_update(mod); rsnd_dvc_volume_update(mod);
}
return change; return change;
} }
static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, static int __rsnd_dvc_pcm_new(struct rsnd_mod *mod,
struct rsnd_dai *rdai, struct rsnd_dai *rdai,
struct snd_soc_pcm_runtime *rtd) struct snd_soc_pcm_runtime *rtd,
const unsigned char *name,
u8 *private)
{ {
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_card *card = rtd->card->snd_card;
struct snd_kcontrol *kctrl; struct snd_kcontrol *kctrl;
static struct snd_kcontrol_new knew = { struct snd_kcontrol_new knew = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Playback Volume", .name = name,
.info = rsnd_dvc_volume_info, .info = rsnd_dvc_volume_info,
.get = rsnd_dvc_volume_get, .get = rsnd_dvc_volume_get,
.put = rsnd_dvc_volume_put, .put = rsnd_dvc_volume_put,
.private_value = (unsigned long)private,
}; };
int ret; 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;
}
kctrl = snd_ctl_new1(&knew, mod); kctrl = snd_ctl_new1(&knew, mod);
if (!kctrl) if (!kctrl)
return -ENOMEM; return -ENOMEM;
...@@ -221,6 +223,33 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, ...@@ -221,6 +223,33 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
return 0; 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;
/* 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;
}
static struct rsnd_mod_ops rsnd_dvc_ops = { static struct rsnd_mod_ops rsnd_dvc_ops = {
.name = DVC_NAME, .name = DVC_NAME,
.probe = rsnd_dvc_probe_gen2, .probe = rsnd_dvc_probe_gen2,
...@@ -239,6 +268,42 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) ...@@ -239,6 +268,42 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)
return &((struct rsnd_dvc *)(priv->dvc) + id)->mod; 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, int rsnd_dvc_probe(struct platform_device *pdev,
const struct rsnd_of_data *of_data, const struct rsnd_of_data *of_data,
struct rsnd_priv *priv) struct rsnd_priv *priv)
...@@ -250,6 +315,8 @@ int rsnd_dvc_probe(struct platform_device *pdev, ...@@ -250,6 +315,8 @@ int rsnd_dvc_probe(struct platform_device *pdev,
char name[RSND_DVC_NAME_SIZE]; char name[RSND_DVC_NAME_SIZE];
int i, nr; int i, nr;
rsnd_of_parse_dvc(pdev, of_data, priv);
nr = info->dvc_info_nr; nr = info->dvc_info_nr;
if (!nr) if (!nr)
return 0; return 0;
......
...@@ -15,63 +15,35 @@ struct rsnd_gen { ...@@ -15,63 +15,35 @@ struct rsnd_gen {
struct rsnd_gen_ops *ops; struct rsnd_gen_ops *ops;
struct regmap *regmap; struct regmap *regmap[RSND_BASE_MAX];
struct regmap_field *regs[RSND_REG_MAX]; struct regmap_field *regs[RSND_REG_MAX];
}; };
#define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen)
#define RSND_REG_SET(gen, id, reg_id, offset, _id_offset, _id_size) \ struct rsnd_regmap_field_conf {
[id] = { \ int idx;
.reg = (unsigned int)gen->base[reg_id] + offset, \ unsigned int reg_offset;
.lsb = 0, \ unsigned int id_offset;
.msb = 31, \ };
.id_size = _id_size, \
#define RSND_REG_SET(id, offset, _id_offset) \
{ \
.idx = id, \
.reg_offset = offset, \
.id_offset = _id_offset, \ .id_offset = _id_offset, \
} }
/* single address mapping */
#define RSND_GEN_S_REG(id, offset) \
RSND_REG_SET(RSND_REG_##id, offset, 0)
/* multi address mapping */
#define RSND_GEN_M_REG(id, offset, _id_offset) \
RSND_REG_SET(RSND_REG_##id, offset, _id_offset)
/* /*
* basic function * 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);
return 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,
};
static int rsnd_is_accessible_reg(struct rsnd_priv *priv, static int rsnd_is_accessible_reg(struct rsnd_priv *priv,
struct rsnd_gen *gen, enum rsnd_reg reg) struct rsnd_gen *gen, enum rsnd_reg reg)
{ {
...@@ -88,6 +60,7 @@ static int rsnd_is_accessible_reg(struct rsnd_priv *priv, ...@@ -88,6 +60,7 @@ static int rsnd_is_accessible_reg(struct rsnd_priv *priv,
u32 rsnd_read(struct rsnd_priv *priv, u32 rsnd_read(struct rsnd_priv *priv,
struct rsnd_mod *mod, enum rsnd_reg reg) 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); struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
u32 val; u32 val;
...@@ -96,6 +69,8 @@ u32 rsnd_read(struct rsnd_priv *priv, ...@@ -96,6 +69,8 @@ u32 rsnd_read(struct rsnd_priv *priv,
regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); 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; return val;
} }
...@@ -103,17 +78,21 @@ void rsnd_write(struct rsnd_priv *priv, ...@@ -103,17 +78,21 @@ void rsnd_write(struct rsnd_priv *priv,
struct rsnd_mod *mod, struct rsnd_mod *mod,
enum rsnd_reg reg, u32 data) enum rsnd_reg reg, u32 data)
{ {
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_gen *gen = rsnd_priv_to_gen(priv); struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
if (!rsnd_is_accessible_reg(priv, gen, reg)) if (!rsnd_is_accessible_reg(priv, gen, reg))
return; return;
regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); 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, void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
enum rsnd_reg reg, u32 mask, u32 data) 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); struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
if (!rsnd_is_accessible_reg(priv, gen, reg)) if (!rsnd_is_accessible_reg(priv, gen, reg))
...@@ -121,35 +100,63 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, ...@@ -121,35 +100,63 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod),
mask, data); mask, data);
dev_dbg(dev, "b %s - 0x%04d : %08x/%08x\n",
rsnd_mod_name(mod), reg, data, mask);
} }
static int rsnd_gen_regmap_init(struct rsnd_priv *priv, #define rsnd_gen_regmap_init(priv, id_size, reg_id, conf) \
struct rsnd_gen *gen, _rsnd_gen_regmap_init(priv, id_size, reg_id, conf, ARRAY_SIZE(conf))
struct reg_field *regf) 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 device *dev = rsnd_priv_to_dev(priv);
struct resource *res;
struct regmap_config regc; struct regmap_config regc;
struct regmap_field *regs;
struct regmap *regmap;
struct reg_field regf;
void __iomem *base;
int i;
memset(&regc, 0, sizeof(regc)); memset(&regc, 0, sizeof(regc));
regc.reg_bits = 32; regc.reg_bits = 32;
regc.val_bits = 32; regc.val_bits = 32;
regc.reg_stride = 4;
gen->regmap = devm_regmap_init(dev, &rsnd_regmap_bus, priv, &regc); res = platform_get_resource(pdev, IORESOURCE_MEM, reg_id);
if (IS_ERR(gen->regmap)) { if (!res)
dev_err(dev, "regmap error %ld\n", PTR_ERR(gen->regmap)); return -ENODEV;
return PTR_ERR(gen->regmap);
}
for (i = 0; i < RSND_REG_MAX; i++) { base = devm_ioremap_resource(dev, res);
gen->regs[i] = NULL; if (IS_ERR(base))
if (!regf[i].reg) return PTR_ERR(base);
continue;
gen->regs[i] = devm_regmap_field_alloc(dev, gen->regmap, regf[i]); regmap = devm_regmap_init_mmio(dev, base, &regc);
if (IS_ERR(gen->regs[i])) if (IS_ERR(regmap))
return PTR_ERR(gen->regs[i]); return PTR_ERR(regmap);
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; return 0;
...@@ -165,15 +172,19 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv, ...@@ -165,15 +172,19 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv,
* *
* ex) R-Car H2 case * ex) R-Car H2 case
* mod / DMAC in / DMAC out / DMAC PP in / DMAC pp out * 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 * 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_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_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc)
#define RDMA_SSI_I_P(addr, i) (addr ##_reg - 0x00141000 + (0x1000 * i)) #define RDMA_SSIU_I_N(addr, i) (addr ##_reg - 0x00441000 + (0x1000 * i))
#define RDMA_SSI_O_P(addr, i) (addr ##_reg - 0x00141000 + (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_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i))
#define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i)) #define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i))
...@@ -184,14 +195,13 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv, ...@@ -184,14 +195,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_N(addr, i) (addr ##_reg - 0x004f8000 + (0x400 * i))
#define RDMA_CMD_O_P(addr, i) (addr ##_reg - 0x001f8000 + (0x400 * i)) #define RDMA_CMD_O_P(addr, i) (addr ##_reg - 0x001f8000 + (0x400 * i))
static void rsnd_gen2_dma_addr(struct rsnd_priv *priv, static dma_addr_t
struct rsnd_dma *dma, rsnd_gen2_dma_addr(struct rsnd_priv *priv,
struct dma_slave_config *cfg, struct rsnd_mod *mod,
int is_play, int slave_id) int is_play, int is_from)
{ {
struct platform_device *pdev = rsnd_priv_to_pdev(priv); struct platform_device *pdev = rsnd_priv_to_pdev(priv);
struct device *dev = rsnd_priv_to_dev(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); struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
dma_addr_t ssi_reg = platform_get_resource(pdev, dma_addr_t ssi_reg = platform_get_resource(pdev,
IORESOURCE_MEM, RSND_GEN2_SSI)->start; IORESOURCE_MEM, RSND_GEN2_SSI)->start;
...@@ -202,179 +212,152 @@ static void rsnd_gen2_dma_addr(struct rsnd_priv *priv, ...@@ -202,179 +212,152 @@ static void rsnd_gen2_dma_addr(struct rsnd_priv *priv,
int use_dvc = !!rsnd_io_to_mod_dvc(io); int use_dvc = !!rsnd_io_to_mod_dvc(io);
int id = rsnd_mod_id(mod); int id = rsnd_mod_id(mod);
struct dma_addr { struct dma_addr {
dma_addr_t src_addr; dma_addr_t out_addr;
dma_addr_t dst_addr; dma_addr_t in_addr;
} dma_addrs[2][2][3] = { } dma_addrs[3][2][3] = {
{ /* SRC */ /* SRC */
{{{ 0, 0 },
/* Capture */ /* Capture */
{{ 0, 0 }, { RDMA_SRC_O_N(src, id), RDMA_SRC_I_P(src, id) },
{ RDMA_SRC_O_N(src, id), 0 }, { RDMA_CMD_O_N(src, id), RDMA_SRC_I_P(src, id) } },
{ RDMA_CMD_O_N(src, id), 0 }},
/* Playback */ /* Playback */
{{ 0, 0, }, {{ 0, 0, },
{ 0, RDMA_SRC_I_N(src, id) }, { RDMA_SRC_O_P(src, id), RDMA_SRC_I_N(src, id) },
{ 0, RDMA_SRC_I_N(src, id) }} { RDMA_CMD_O_P(src, id), RDMA_SRC_I_N(src, id) } }
}, { /* SSI */ },
/* SSI */
/* Capture */ /* Capture */
{{ RDMA_SSI_O_N(ssi, id), 0 }, {{{ RDMA_SSI_O_N(ssi, id), 0 },
{ RDMA_SSI_O_P(ssi, id), RDMA_SRC_I_P(src, id) }, { RDMA_SSIU_O_P(ssi, id), 0 },
{ RDMA_SSI_O_P(ssi, id), RDMA_SRC_I_P(src, id) }}, { RDMA_SSIU_O_P(ssi, id), 0 } },
/* Playback */ /* Playback */
{{ 0, RDMA_SSI_I_N(ssi, id) }, {{ 0, RDMA_SSI_I_N(ssi, id) },
{ RDMA_SRC_O_P(src, id), RDMA_SSI_I_P(ssi, id) }, { 0, RDMA_SSIU_I_P(ssi, id) },
{ RDMA_CMD_O_P(src, id), RDMA_SSI_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), 0 },
{ RDMA_SSIU_O_P(ssi, id), 0 } },
/* Playback */
{{ 0, RDMA_SSIU_I_N(ssi, id) },
{ 0, RDMA_SSIU_I_P(ssi, id) },
{ 0, RDMA_SSIU_I_P(ssi, id) } } },
}; };
/* it shouldn't happen */ /* it shouldn't happen */
if (use_dvc & !use_src) { if (use_dvc & !use_src)
dev_err(dev, "DVC is selected without SRC\n"); dev_err(dev, "DVC is selected without SRC\n");
return;
}
cfg->src_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].src_addr; /* use SSIU or SSI ? */
cfg->dst_addr = dma_addrs[is_ssi][is_play][use_src + use_dvc].dst_addr; if (is_ssi && (0 == strcmp(rsnd_mod_dma_name(mod), "ssiu")))
is_ssi++;
dev_dbg(dev, "dma%d addr - src : %x / dst : %x\n", return (is_from) ?
id, cfg->src_addr, cfg->dst_addr); 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, dma_addr_t rsnd_gen_dma_addr(struct rsnd_priv *priv,
struct rsnd_dma *dma, struct rsnd_mod *mod,
struct dma_slave_config *cfg, int is_play, int is_from)
int is_play, int slave_id)
{ {
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 * gen1 uses default DMA addr
*/ */
if (rsnd_is_gen1(priv)) 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 * 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, static int rsnd_gen2_probe(struct platform_device *pdev,
struct rsnd_priv *priv) struct rsnd_priv *priv)
{ {
struct device *dev = rsnd_priv_to_dev(priv); struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_gen *gen = rsnd_priv_to_gen(priv); struct rsnd_regmap_field_conf conf_ssiu[] = {
struct resource *scu_res; RSND_GEN_S_REG(SSI_MODE0, 0x800),
struct resource *adg_res; RSND_GEN_S_REG(SSI_MODE1, 0x804),
struct resource *ssiu_res; /* FIXME: it needs SSI_MODE2/3 in the future */
struct resource *ssi_res; RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80),
int ret; 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),
* map address RSND_GEN_M_REG(INT_ENABLE, 0x18, 0x80),
*/ };
scu_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SCU); struct rsnd_regmap_field_conf conf_scu[] = {
adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_ADG); RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x0, 0x20),
ssiu_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSIU); RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20),
ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSI); RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20),
RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20),
gen->base[RSND_GEN2_SCU] = devm_ioremap_resource(dev, scu_res); RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20),
gen->base[RSND_GEN2_ADG] = devm_ioremap_resource(dev, adg_res); RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40),
gen->base[RSND_GEN2_SSIU] = devm_ioremap_resource(dev, ssiu_res); RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40),
gen->base[RSND_GEN2_SSI] = devm_ioremap_resource(dev, ssi_res); RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40),
if (IS_ERR(gen->base[RSND_GEN2_SCU]) || RSND_GEN_M_REG(SRC_IFSCR, 0x21c, 0x40),
IS_ERR(gen->base[RSND_GEN2_ADG]) || RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40),
IS_ERR(gen->base[RSND_GEN2_SSIU]) || RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40),
IS_ERR(gen->base[RSND_GEN2_SSI])) RSND_GEN_M_REG(SRC_BSDSR, 0x22c, 0x40),
return -ENODEV; RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40),
RSND_GEN_M_REG(DVC_SWRSR, 0xe00, 0x100),
ret = rsnd_gen2_regmap_init(priv, gen); RSND_GEN_M_REG(DVC_DVUIR, 0xe04, 0x100),
if (ret < 0) RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100),
return ret; RSND_GEN_M_REG(DVC_DVUCR, 0xe10, 0x100),
RSND_GEN_M_REG(DVC_ZCMCR, 0xe14, 0x100),
dev_dbg(dev, "Gen2 device probed\n"); RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100),
dev_dbg(dev, "SCU : %pap => %p\n", &scu_res->start, RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100),
gen->base[RSND_GEN2_SCU]); RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100),
dev_dbg(dev, "ADG : %pap => %p\n", &adg_res->start, };
gen->base[RSND_GEN2_ADG]); struct rsnd_regmap_field_conf conf_adg[] = {
dev_dbg(dev, "SSIU : %pap => %p\n", &ssiu_res->start, RSND_GEN_S_REG(BRRA, 0x00),
gen->base[RSND_GEN2_SSIU]); RSND_GEN_S_REG(BRRB, 0x04),
dev_dbg(dev, "SSI : %pap => %p\n", &ssi_res->start, RSND_GEN_S_REG(SSICKR, 0x08),
gen->base[RSND_GEN2_SSI]); 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; return 0;
} }
...@@ -383,92 +366,60 @@ static int rsnd_gen2_probe(struct platform_device *pdev, ...@@ -383,92 +366,60 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
* Gen1 * 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, static int rsnd_gen1_probe(struct platform_device *pdev,
struct rsnd_priv *priv) struct rsnd_priv *priv)
{ {
struct device *dev = rsnd_priv_to_dev(priv); struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_gen *gen = rsnd_priv_to_gen(priv); struct rsnd_regmap_field_conf conf_sru[] = {
struct resource *sru_res; RSND_GEN_S_REG(SRC_ROUTE_SEL, 0x00),
struct resource *adg_res; RSND_GEN_S_REG(SRC_TMG_SEL0, 0x08),
struct resource *ssi_res; RSND_GEN_S_REG(SRC_TMG_SEL1, 0x0c),
int ret; RSND_GEN_S_REG(SRC_TMG_SEL2, 0x10),
RSND_GEN_S_REG(SRC_ROUTE_CTRL, 0xc0),
/* RSND_GEN_S_REG(SSI_MODE0, 0xD0),
* map address RSND_GEN_S_REG(SSI_MODE1, 0xD4),
*/ RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x20, 0x4),
sru_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU); RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0x50, 0x8),
adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_ADG); RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40),
ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SSI); RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40),
RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40),
gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res); RSND_GEN_M_REG(SRC_IFSCR, 0x21c, 0x40),
gen->base[RSND_GEN1_ADG] = devm_ioremap_resource(dev, adg_res); RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40),
gen->base[RSND_GEN1_SSI] = devm_ioremap_resource(dev, ssi_res); RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40),
if (IS_ERR(gen->base[RSND_GEN1_SRU]) || RSND_GEN_M_REG(SRC_MNFSR, 0x228, 0x40),
IS_ERR(gen->base[RSND_GEN1_ADG]) || };
IS_ERR(gen->base[RSND_GEN1_SSI])) struct rsnd_regmap_field_conf conf_adg[] = {
return -ENODEV; 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); ret_sru = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SRU, conf_sru);
if (ret < 0) ret_adg = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, conf_adg);
return ret; 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, "Gen1 is 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]);
return 0; return 0;
} }
/* /*
......
...@@ -90,6 +90,7 @@ enum rsnd_reg { ...@@ -90,6 +90,7 @@ enum rsnd_reg {
RSND_REG_SHARE19, RSND_REG_SHARE19,
RSND_REG_SHARE20, RSND_REG_SHARE20,
RSND_REG_SHARE21, RSND_REG_SHARE21,
RSND_REG_SHARE22,
RSND_REG_MAX, RSND_REG_MAX,
}; };
...@@ -127,6 +128,7 @@ enum rsnd_reg { ...@@ -127,6 +128,7 @@ enum rsnd_reg {
#define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19 #define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19
#define RSND_REG_CMD_CTRL RSND_REG_SHARE20 #define RSND_REG_CMD_CTRL RSND_REG_SHARE20
#define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21 #define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21
#define RSND_REG_BUSIF_DALIGN RSND_REG_SHARE22
struct rsnd_of_data; struct rsnd_of_data;
struct rsnd_priv; struct rsnd_priv;
...@@ -156,12 +158,9 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod); ...@@ -156,12 +158,9 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod);
*/ */
struct rsnd_dma { struct rsnd_dma {
struct sh_dmae_slave slave; struct sh_dmae_slave slave;
struct work_struct work;
struct dma_chan *chan; struct dma_chan *chan;
enum dma_data_direction dir; enum dma_transfer_direction dir;
dma_addr_t addr;
int submit_loop;
int offset; /* it cares A/B plane */
}; };
void rsnd_dma_start(struct rsnd_dma *dma); void rsnd_dma_start(struct rsnd_dma *dma);
...@@ -185,6 +184,7 @@ enum rsnd_mod_type { ...@@ -185,6 +184,7 @@ enum rsnd_mod_type {
struct rsnd_mod_ops { struct rsnd_mod_ops {
char *name; char *name;
char* (*dma_name)(struct rsnd_mod *mod);
int (*probe)(struct rsnd_mod *mod, int (*probe)(struct rsnd_mod *mod,
struct rsnd_dai *rdai); struct rsnd_dai *rdai);
int (*remove)(struct rsnd_mod *mod, int (*remove)(struct rsnd_mod *mod,
...@@ -224,6 +224,7 @@ void rsnd_mod_init(struct rsnd_priv *priv, ...@@ -224,6 +224,7 @@ void rsnd_mod_init(struct rsnd_priv *priv,
enum rsnd_mod_type type, enum rsnd_mod_type type,
int id); int id);
char *rsnd_mod_name(struct rsnd_mod *mod); char *rsnd_mod_name(struct rsnd_mod *mod);
char *rsnd_mod_dma_name(struct rsnd_mod *mod);
/* /*
* R-Car sound DAI * R-Car sound DAI
...@@ -281,10 +282,9 @@ int rsnd_gen_probe(struct platform_device *pdev, ...@@ -281,10 +282,9 @@ int rsnd_gen_probe(struct platform_device *pdev,
void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
struct rsnd_mod *mod, struct rsnd_mod *mod,
enum rsnd_reg reg); enum rsnd_reg reg);
void rsnd_gen_dma_addr(struct rsnd_priv *priv, dma_addr_t rsnd_gen_dma_addr(struct rsnd_priv *priv,
struct rsnd_dma *dma, struct rsnd_mod *mod,
struct dma_slave_config *cfg, int is_play, int is_from);
int is_play, int slave_id);
#define rsnd_is_gen1(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1) #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) #define rsnd_is_gen2(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2)
...@@ -391,8 +391,12 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); ...@@ -391,8 +391,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, unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
struct rsnd_dai_stream *io, struct rsnd_dai_stream *io,
struct snd_pcm_runtime *runtime); struct snd_pcm_runtime *runtime);
int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai); 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, int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai); struct rsnd_dai *rdai);
......
...@@ -106,18 +106,19 @@ struct rsnd_src { ...@@ -106,18 +106,19 @@ struct rsnd_src {
/* /*
* Gen1/Gen2 common functions * Gen1/Gen2 common functions
*/ */
int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai) struct rsnd_dai *rdai,
int use_busif)
{ {
struct rsnd_dai_stream *io = rsnd_mod_to_io(ssi_mod); struct rsnd_dai_stream *io = rsnd_mod_to_io(ssi_mod);
struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
int ssi_id = rsnd_mod_id(ssi_mod); int ssi_id = rsnd_mod_id(ssi_mod);
/* /*
* SSI_MODE0 * SSI_MODE0
*/ */
rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id), rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id),
src_mod ? 0 : (1 << ssi_id)); !use_busif << ssi_id);
/* /*
* SSI_MODE1 * SSI_MODE1
...@@ -143,6 +144,46 @@ int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, ...@@ -143,6 +144,46 @@ int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod,
0x2 << shift : 0x1 << shift); 0x2 << shift : 0x1 << shift);
} }
/*
* 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;
}
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; return 0;
} }
...@@ -461,18 +502,45 @@ static struct rsnd_mod_ops rsnd_src_gen1_ops = { ...@@ -461,18 +502,45 @@ static struct rsnd_mod_ops rsnd_src_gen1_ops = {
static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
struct rsnd_dai *rdai) 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; 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); ret = rsnd_src_set_convert_rate(mod, rdai);
if (ret < 0) if (ret < 0)
return ret; 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_SRCCR, 0x00011110);
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); rsnd_mod_write(mod, SRC_BSDSR, 0x01800000);
break;
}
rsnd_mod_write(mod, SRC_BSISR, 0x00100060); rsnd_mod_write(mod, SRC_BSISR, 0x00100060);
return 0; return 0;
...@@ -554,7 +622,6 @@ static int rsnd_src_start_gen2(struct rsnd_mod *mod, ...@@ -554,7 +622,6 @@ static int rsnd_src_start_gen2(struct rsnd_mod *mod,
rsnd_dma_start(rsnd_mod_to_dma(&src->mod)); rsnd_dma_start(rsnd_mod_to_dma(&src->mod));
rsnd_mod_write(mod, SSI_CTRL, 0x1);
rsnd_mod_write(mod, SRC_CTRL, val); rsnd_mod_write(mod, SRC_CTRL, val);
return rsnd_src_start(mod, rdai); return rsnd_src_start(mod, rdai);
...@@ -565,7 +632,6 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod, ...@@ -565,7 +632,6 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
{ {
struct rsnd_src *src = rsnd_mod_to_src(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_mod_write(mod, SRC_CTRL, 0);
rsnd_dma_stop(rsnd_mod_to_dma(&src->mod)); rsnd_dma_stop(rsnd_mod_to_dma(&src->mod));
......
...@@ -90,6 +90,20 @@ struct rsnd_ssi { ...@@ -90,6 +90,20 @@ struct rsnd_ssi {
#define rsnd_ssi_mode_flags(p) ((p)->info->flags) #define rsnd_ssi_mode_flags(p) ((p)->info->flags)
#define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) #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, static void rsnd_ssi_status_check(struct rsnd_mod *mod,
u32 bit) u32 bit)
{ {
...@@ -289,8 +303,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, ...@@ -289,8 +303,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
ssi->cr_own = cr; ssi->cr_own = cr;
ssi->err = -1; /* ignore 1st error */ ssi->err = -1; /* ignore 1st error */
rsnd_src_ssi_mode_init(mod, rdai);
return 0; return 0;
} }
...@@ -389,6 +401,8 @@ static int rsnd_ssi_pio_start(struct rsnd_mod *mod, ...@@ -389,6 +401,8 @@ static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
/* enable PIO IRQ */ /* enable PIO IRQ */
ssi->cr_etc = UIEN | OIEN | DIEN; ssi->cr_etc = UIEN | OIEN | DIEN;
rsnd_src_ssiu_start(mod, rdai, 0);
rsnd_src_enable_ssi_irq(mod, rdai); rsnd_src_enable_ssi_irq(mod, rdai);
rsnd_ssi_hw_start(ssi, rdai, io); rsnd_ssi_hw_start(ssi, rdai, io);
...@@ -405,6 +419,8 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod, ...@@ -405,6 +419,8 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod,
rsnd_ssi_hw_stop(ssi, rdai); rsnd_ssi_hw_stop(ssi, rdai);
rsnd_src_ssiu_stop(mod, rdai, 0);
return 0; return 0;
} }
...@@ -457,6 +473,8 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod, ...@@ -457,6 +473,8 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
/* enable DMA transfer */ /* enable DMA transfer */
ssi->cr_etc = DMEN; ssi->cr_etc = DMEN;
rsnd_src_ssiu_start(mod, rdai, rsnd_ssi_use_busif(mod));
rsnd_dma_start(dma); rsnd_dma_start(dma);
rsnd_ssi_hw_start(ssi, ssi->rdai, io); rsnd_ssi_hw_start(ssi, ssi->rdai, io);
...@@ -482,11 +500,19 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, ...@@ -482,11 +500,19 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
rsnd_dma_stop(dma); rsnd_dma_stop(dma);
rsnd_src_ssiu_stop(mod, rdai, 1);
return 0; 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 = { static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
.name = SSI_NAME, .name = SSI_NAME,
.dma_name = rsnd_ssi_dma_name,
.probe = rsnd_ssi_dma_probe, .probe = rsnd_ssi_dma_probe,
.remove = rsnd_ssi_dma_remove, .remove = rsnd_ssi_dma_remove,
.init = rsnd_ssi_init, .init = rsnd_ssi_init,
...@@ -595,6 +621,9 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev, ...@@ -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) ? ssi_info->dma_id = of_get_property(np, "pio-transfer", NULL) ?
0 : 1; 0 : 1;
if (of_get_property(np, "no-busif", NULL))
ssi_info->flags |= RSND_SSI_NO_BUSIF;
} }
rsnd_of_parse_ssi_end: rsnd_of_parse_ssi_end:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册