req->to_memory = false;
req->dest_addr = i2s_get_fifo_phy_base(ads->i2s_phys, I2S_FIFO_TX);
req->dest_wrap = 4;
- req->dest_bus_width = 16;
+ if (ads->bit_format == TEGRA_AUDIO_BIT_FORMAT_DSP)
+ req->dest_bus_width = ads->pdata->dsp_bus_width;
+ else
+ req->dest_bus_width = ads->pdata->i2s_bus_width;
req->source_bus_width = 32;
req->source_wrap = 0;
req->req_sel = ads->dma_req_sel;
req->to_memory = true;
req->source_addr = i2s_get_fifo_phy_base(ads->i2s_phys, I2S_FIFO_RX);
req->source_wrap = 4;
- req->source_bus_width = 16;
+ if (ads->bit_format == TEGRA_AUDIO_BIT_FORMAT_DSP)
+ req->source_bus_width = ads->pdata->dsp_bus_width;
+ else
+ req->source_bus_width = ads->pdata->i2s_bus_width;
req->dest_bus_width = 32;
req->dest_wrap = 0;
req->req_sel = ads->dma_req_sel;
int rc = 0;
struct audio_driver_state *ads = ads_from_misc_ctl(file);
unsigned int mode;
+ bool dma_restart = false;
+
+ mutex_lock(&ads->out.lock);
+ mutex_lock(&ads->in.lock);
switch (cmd) {
case TEGRA_AUDIO_SET_BIT_FORMAT:
if (copy_from_user(&mode, (const void __user *)arg,
sizeof(mode))) {
rc = -EFAULT;
- break;
+ goto done;
}
- switch(mode) {
+ dma_restart = (mode != ads->bit_format);
+ switch (mode) {
case TEGRA_AUDIO_BIT_FORMAT_DEFAULT:
i2s_set_bit_format(ads->i2s_base, ads->pdata->mode);
ads->bit_format = mode;
default:
pr_err("%s: Invald PCM mode %d", __func__, mode);
rc = -EINVAL;
- break;
+ goto done;
}
break;
case TEGRA_AUDIO_GET_BIT_FORMAT:
if (copy_to_user((void __user *)arg, &ads->bit_format,
- sizeof(mode))) {
+ sizeof(mode)))
rc = -EFAULT;
+ goto done;
+ }
+
+ if (dma_restart && ads->using_dma) {
+ pr_debug("%s: Restarting DMA due to configuration change.\n",
+ __func__);
+ if (kfifo_len(&ads->out.fifo) || ads->in.active) {
+ pr_err("%s: dma busy, cannot restart.\n", __func__);
+ rc = -EBUSY;
+ goto done;
}
- break;
+ sound_ops->tear_down(ads);
+ sound_ops->setup(ads);
}
+
+done:
+ mutex_unlock(&ads->in.lock);
+ mutex_unlock(&ads->out.lock);
return rc;
}