static int cygnus_pcm_open(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; struct cygnus_aio_port *aio; int ret; aio = cygnus_dai_get_dma_data(substream); if (!aio) return -ENODEV; dev_dbg(rtd->cpu_dai->dev, "%s port %d\n", __func__, aio->portnum); snd_soc_set_runtime_hwparams(substream, &cygnus_pcm_hw); ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, PERIOD_BYTES_MIN); if (ret < 0) return ret; ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, PERIOD_BYTES_MIN); if (ret < 0) return ret; /* * Keep track of which substream belongs to which port. * This info is needed by snd_pcm_period_elapsed() in irq_handler */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) aio->play_stream = substream; else aio->capture_stream = substream; return 0; }
static int lola_pcm_open(struct snd_pcm_substream *substream) { struct lola *chip = snd_pcm_substream_chip(substream); struct lola_pcm *pcm = lola_get_pcm(substream); struct lola_stream *str = lola_get_stream(substream); struct snd_pcm_runtime *runtime = substream->runtime; mutex_lock(&chip->open_mutex); if (str->opened) { mutex_unlock(&chip->open_mutex); return -EBUSY; } str->substream = substream; str->master = NULL; str->opened = 1; runtime->hw = lola_pcm_hw; runtime->hw.channels_max = pcm->num_streams - str->index; if (chip->sample_rate) { /* sample rate is locked */ runtime->hw.rate_min = chip->sample_rate; runtime->hw.rate_max = chip->sample_rate; } else { runtime->hw.rate_min = chip->sample_rate_min; runtime->hw.rate_max = chip->sample_rate_max; } chip->ref_count_rate++; snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); /* period size = multiple of chip->granularity (8, 16 or 32 frames)*/ snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, chip->granularity); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, chip->granularity); mutex_unlock(&chip->open_mutex); return 0; }
static int msm_lsm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct lsm_priv *prtd; int ret = 0; pr_debug("%s\n", __func__); prtd = kzalloc(sizeof(struct lsm_priv), GFP_KERNEL); if (!prtd) { pr_err("%s: Failed to allocate memory for lsm_priv\n", __func__); return -ENOMEM; } spin_lock_init(&prtd->event_lock); init_waitqueue_head(&prtd->event_wait); prtd->substream = substream; runtime->private_data = prtd; runtime->hw = msm_pcm_hardware_capture; ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_sample_rates); if (ret < 0) pr_info("%s: snd_pcm_hw_constraint_list failed ret %d\n", __func__, ret); /* Ensure that buffer size is a multiple of period size */ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) pr_info("%s: snd_pcm_hw_constraint_integer failed ret %d\n", __func__, ret); ret = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, CAPTURE_MIN_NUM_PERIODS * CAPTURE_MIN_PERIOD_SIZE, CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE); if (ret < 0) pr_info("%s: constraint for buffer bytes min max ret = %d\n", __func__, ret); ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); if (ret < 0) { pr_info("%s: constraint for period bytes step ret = %d\n", __func__, ret); } ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); if (ret < 0) pr_info("%s: constraint for buffer bytes step ret = %d\n", __func__, ret); prtd->lsm_client = q6lsm_client_alloc( (lsm_app_cb)lsm_event_handler, prtd); if (!prtd->lsm_client) { pr_err("%s: Could not allocate memory\n", __func__); kfree(prtd); runtime->private_data = NULL; return -ENOMEM; } return 0; }
static int pxa910_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; struct pxa910_runtime_data *prtd; int ret; snd_soc_set_runtime_hwparams(substream, &pxa910_pcm_hardware); /* * For mysterious reasons (and despite what the manual says) * playback samples are lost if the DMA count is not a multiple * of the DMA burst size. Let's add a rule to enforce that. */ ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); if (ret) goto out; ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); if (ret) goto out; ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) goto out; prtd = kzalloc(sizeof(struct pxa910_runtime_data), GFP_KERNEL); if (prtd == NULL) { ret = -ENOMEM; goto out; } prtd->dma_ch = -1; prtd->squ_desc_array = prtd->squ_desc_array = pxa910_sram_alloc(PAGE_SIZE, &prtd->squ_desc_array_phys); if (!prtd->squ_desc_array) { ret = -ENOMEM; goto err1; } runtime->private_data = prtd; return 0; err1: kfree(prtd); out: return ret; }
static int hdmi_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdmi_audio_data *ad = card_drvdata_substream(substream); int ret; /* * Make sure that the period bytes are multiple of the DMA packet size. * Largest packet size we use is 32 32-bit words = 128 bytes */ ret = snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); if (ret < 0) { dev_err(dai->dev, "could not apply constraint\n"); return ret; } snd_soc_dai_set_dma_data(dai, substream, &ad->dma_data); mutex_lock(&ad->current_stream_lock); ad->current_stream = substream; mutex_unlock(&ad->current_stream_lock); ret = ad->ops->audio_startup(ad->dssdev, hdmi_dai_abort); if (ret) { mutex_lock(&ad->current_stream_lock); ad->current_stream = NULL; mutex_unlock(&ad->current_stream_lock); } return ret; }
/* open_playback callback */ static int snd_ca0106_pcm_open_playback_channel(snd_pcm_substream_t *substream, int channel_id) { ca0106_t *chip = snd_pcm_substream_chip(substream); ca0106_channel_t *channel = &(chip->playback_channels[channel_id]); ca0106_pcm_t *epcm; snd_pcm_runtime_t *runtime = substream->runtime; int err; epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) return -ENOMEM; epcm->emu = chip; epcm->substream = substream; epcm->channel_id=channel_id; runtime->private_data = epcm; runtime->private_free = snd_ca0106_pcm_free_substream; runtime->hw = snd_ca0106_playback_hw; channel->emu = chip; channel->number = channel_id; channel->use=1; //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel); //channel->interrupt = snd_ca0106_pcm_channel_interrupt; channel->epcm=epcm; if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0) return err; return 0; }
static int omap_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct omap_runtime_data *prtd; int ret; snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware); /* Ensure that buffer size is a multiple of period size */ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) goto out; if (cpu_is_omap44xx()) { /* ABE needs a step of 24 * 4 data bits, and HDMI 32 * 4 * Ensure buffer size satisfies both constraints. */ ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 384); if (ret < 0) goto out; } prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); if (prtd == NULL) { ret = -ENOMEM; goto out; } spin_lock_init(&prtd->lock); runtime->private_data = prtd; out: return ret; }
int __pxa2xx_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct pxa2xx_runtime_data *rtd; int ret; runtime->hw = pxa2xx_pcm_hardware; /* * For mysterious reasons (and despite what the manual says) * playback samples are lost if the DMA count is not a multiple * of the DMA burst size. Let's add a rule to enforce that. */ ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); if (ret) goto out; ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); if (ret) goto out; ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) goto out; ret = -ENOMEM; rtd = kzalloc(sizeof(*rtd), GFP_KERNEL); if (!rtd) goto out; rtd->dma_desc_array = dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE, &rtd->dma_desc_array_phys, GFP_KERNEL); if (!rtd->dma_desc_array) goto err1; rtd->dma_ch = -1; runtime->private_data = rtd; return 0; err1: kfree(rtd); out: return ret; }
int __pxa2xx_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct pxa2xx_runtime_data *rtd; int ret; runtime->hw = pxa2xx_pcm_hardware; /* */ ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); if (ret) goto out; ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); if (ret) goto out; ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) goto out; ret = -ENOMEM; rtd = kzalloc(sizeof(*rtd), GFP_KERNEL); if (!rtd) goto out; rtd->dma_desc_array = dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE, &rtd->dma_desc_array_phys, GFP_KERNEL); if (!rtd->dma_desc_array) goto err1; rtd->dma_ch = -1; runtime->private_data = rtd; return 0; err1: kfree(rtd); out: return ret; }
static int tegra_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct tegra_runtime_data *prtd; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct tegra_pcm_dma_params * dmap; int ret = 0; prtd = kzalloc(sizeof(struct tegra_runtime_data), GFP_KERNEL); if (prtd == NULL) return -ENOMEM; runtime->private_data = prtd; prtd->substream = substream; spin_lock_init(&prtd->lock); dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if (dmap) { prtd->dma_req[0].dev = prtd; prtd->dma_req[1].dev = prtd; prtd->dma_chan = tegra_dma_allocate_channel( TEGRA_DMA_MODE_CONTINUOUS_SINGLE, "pcm"); if (prtd->dma_chan == NULL) { ret = -ENOMEM; goto err; } } /* Set HW params now that initialization is complete */ snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware); /* Ensure period size is multiple of 8 */ ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 0x8); if (ret < 0) goto err; /* Ensure that buffer size is a multiple of period size */ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) goto err; return 0; err: if (prtd->dma_chan) { tegra_dma_free_channel(prtd->dma_chan); } kfree(prtd); return ret; }
static int lx_pcm_open(struct snd_pcm_substream *substream) { struct lx6464es *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err = 0; int board_rate; dev_dbg(chip->card->dev, "->lx_pcm_open\n"); mutex_lock(&chip->setup_mutex); /* copy the struct snd_pcm_hardware struct */ runtime->hw = lx_caps; #if 0 /* buffer-size should better be multiple of period-size */ err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (err < 0) { dev_warn(chip->card->dev, "could not constrain periods\n"); goto exit; } #endif /* the clock rate cannot be changed */ board_rate = chip->board_sample_rate; err = snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_RATE, board_rate); if (err < 0) { dev_warn(chip->card->dev, "could not constrain periods\n"); goto exit; } /* constrain period size */ err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, MICROBLAZE_IBL_MIN, MICROBLAZE_IBL_MAX); if (err < 0) { dev_warn(chip->card->dev, "could not constrain period size\n"); goto exit; } snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32); snd_pcm_set_sync(substream); err = 0; exit: runtime->private_data = chip; mutex_unlock(&chip->setup_mutex); dev_dbg(chip->card->dev, "<-lx_pcm_open, %d\n", err); return err; }
static int cns3xxx_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct cns3xxx_runtime_data *prtd; int ret; #ifdef __DEBUG_PATH printk("%s=>%d\n", __FUNCTION__, __LINE__); #endif snd_soc_set_runtime_hwparams(substream, &cns3xxx_pcm_hardware); /* Enforcing the constraint that period bytes are a multiple of 16 bytes. * This helps PL330 GDMA innerloop */ ret = snd_pcm_hw_constraint_step (runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,16); if (ret) goto out; ret = snd_pcm_hw_constraint_step (runtime,0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,16); if (ret) goto out; /* To ensure that buffersize is a multiple of period size ? */ ret = snd_pcm_hw_constraint_integer (runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) goto out; prtd = kzalloc(sizeof(struct cns3xxx_runtime_data), GFP_KERNEL); if (prtd == NULL) { ret = -ENOMEM; goto out; } prtd->dma_ch = -1; runtime->private_data = prtd; return 0; out: printk("%s=>%d\n", __FUNCTION__, __LINE__); return ret; }
static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { int err; err = snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); if (err < 0) return err; return 0; }
static int aess_open(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_platform *platform = rtd->platform; struct omap_abe *abe = snd_soc_platform_get_drvdata(platform); struct snd_soc_dai *dai = rtd->cpu_dai; int ret = 0; mutex_lock(&abe->mutex); dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); switch (dai->id) { case OMAP_ABE_FRONTEND_DAI_MODEM: break; case OMAP_ABE_FRONTEND_DAI_LP_MEDIA: snd_soc_set_runtime_hwparams(substream, &omap_abe_hardware); ret = snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 1024); break; default: /* * Period size must be aligned with the Audio Engine * processing loop which is 250 us long */ ret = snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, omap_abe_hwrule_period_step, NULL, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); break; } if (ret < 0) { dev_err(abe->dev, "failed to set period constraints for DAI %d\n", dai->id); goto out; } omap_abe_pm_runtime_get_sync(abe); if (!abe->active++) { abe->opp.level = 0; ret = abe_pm_restore_context(abe); if (ret) goto out; omap_aess_wakeup(abe->aess); } out: mutex_unlock(&abe->mutex); return ret; }
static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { int err; /* * Make sure that the period bytes are multiple of the DMA packet size. * Largest packet size we use is 32 32-bit words = 128 bytes */ err = snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); if (err < 0) return err; return 0; }
static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai); int bus_id = mcbsp_data->bus_id; int err = 0; if (!cpu_dai->active) { err = omap_mcbsp_request(bus_id); cpu_dai->active = 1; } /* * OMAP3 McBSP FIFO is word structured. * McBSP2 has 1024 + 256 = 1280 word long buffer, * McBSP1,3,4,5 has 128 word long buffer * This means that the size of the FIFO depends on the sample format. * For example on McBSP3: * 16bit samples: size is 128 * 2 = 256 bytes * 32bit samples: size is 128 * 4 = 512 bytes * It is simpler to place constraint for buffer and period based on * channels. * McBSP3 as example again (16 or 32 bit samples): * 1 channel (mono): size is 128 frames (128 words) * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words) * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words) */ if (cpu_is_omap34xx() || cpu_is_omap44xx()) { /* * Rule for the buffer size. We should not allow * smaller buffer than the FIFO size to avoid underruns */ #if 0 // FIXME: All BE must support hw_rules and constraints */ snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, omap_mcbsp_hwrule_min_buffersize, mcbsp_data, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1); /* Make sure, that the period size is always even */ snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2); #endif } return err; }
static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); int err = 0; if (!cpu_dai->active) err = omap_mcbsp_request(mcbsp); /* * OMAP3 McBSP FIFO is word structured. * McBSP2 has 1024 + 256 = 1280 word long buffer, * McBSP1,3,4,5 has 128 word long buffer * This means that the size of the FIFO depends on the sample format. * For example on McBSP3: * 16bit samples: size is 128 * 2 = 256 bytes * 32bit samples: size is 128 * 4 = 512 bytes * It is simpler to place constraint for buffer and period based on * channels. * McBSP3 as example again (16 or 32 bit samples): * 1 channel (mono): size is 128 frames (128 words) * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words) * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words) */ if (mcbsp->pdata->buffer_size) { /* * Rule for the buffer size. We should not allow * smaller buffer than the FIFO size to avoid underruns. * This applies only for the playback stream. */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, omap_mcbsp_hwrule_min_buffersize, mcbsp, SNDRV_PCM_HW_PARAM_CHANNELS, -1); /* Make sure, that the period size is always even */ snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2); } snd_soc_dai_set_dma_data(cpu_dai, substream, &mcbsp->dma_data[substream->stream]); return err; }
static int snd_atiixp_playback_open(snd_pcm_substream_t *substream) { atiixp_t *chip = snd_pcm_substream_chip(substream); int err; down(&chip->open_mutex); err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0); up(&chip->open_mutex); if (err < 0) return err; substream->runtime->hw.channels_max = chip->max_channels; if (chip->max_channels > 2) /* channels must be even */ snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2); return 0; }
static int sst_media_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { int ret_val = 0; struct snd_pcm_runtime *runtime = substream->runtime; struct sst_runtime_stream *stream; stream = kzalloc(sizeof(*stream), GFP_KERNEL); if (!stream) return -ENOMEM; spin_lock_init(&stream->status_lock); /* get the sst ops */ mutex_lock(&sst_dsp_lock); if (!sst_dsp || !try_module_get(sst_dsp->dev->driver->owner)) { pr_err("no device available to run\n"); ret_val = -ENODEV; goto out_ops; } stream->ops = sst_dsp->ops; mutex_unlock(&sst_dsp_lock); stream->stream_info.str_id = 0; sst_set_stream_status(stream, SST_PLATFORM_UNINIT); stream->stream_info.mad_substream = substream; runtime->private_data = stream; if (strstr(dai->name, "Power-cpu-dai")) return power_up_sst(stream); /* Make sure, that the period size is always even */ snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS, 2); pr_debug("buf_ptr %llu\n", stream->stream_info.buffer_ptr); return snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); out_ops: kfree(stream); mutex_unlock(&sst_dsp_lock); return ret_val; }
static int sst_media_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { int ret_val = 0; struct snd_pcm_runtime *runtime = substream->runtime; struct sst_runtime_stream *stream; stream = kzalloc(sizeof(*stream), GFP_KERNEL); if (!stream) return -ENOMEM; spin_lock_init(&stream->status_lock); /* get the sst ops */ mutex_lock(&sst_lock); if (!sst || !try_module_get(sst->dev->driver->owner)) { dev_err(dai->dev, "no device available to run\n"); ret_val = -ENODEV; goto out_ops; } stream->ops = sst->ops; mutex_unlock(&sst_lock); stream->stream_info.str_id = 0; stream->stream_info.arg = substream; /* allocate memory for SST API set */ runtime->private_data = stream; ret_val = power_up_sst(stream); if (ret_val < 0) return ret_val; /* Make sure, that the period size is always even */ snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS, 2); return snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); out_ops: kfree(stream); mutex_unlock(&sst_lock); return ret_val; }
static int snd_ps3_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); int pcm_index; pcm_index = substream->pcm->device; card->substream = substream; runtime->hw = snd_ps3_pcm_hw; card->start_delay = snd_ps3_start_delay; snd_ps3_mute(0); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, PS3_AUDIO_FIFO_STAGE_SIZE * 4 * 2); return 0; };
/* * PCM operators */ static int snd_ps3_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream); int pcm_index; pcm_index = substream->pcm->device; /* to retrieve substream/runtime in interrupt handler */ card->substream = substream; runtime->hw = snd_ps3_pcm_hw; card->start_delay = snd_ps3_start_delay; /* mute off */ snd_ps3_mute(0); /* this function sleep */ snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, PS3_AUDIO_FIFO_STAGE_SIZE * 4 * 2); return 0; };
static int tegra_pcm_open(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct device *dev = rtd->platform->dev; struct tegra_runtime_data *prtd; int ret; if (rtd->dai_link->no_pcm) return 0; prtd = kzalloc(sizeof(struct tegra_runtime_data), GFP_KERNEL); if (prtd == NULL) return -ENOMEM; /* Set HW params now that initialization is complete */ snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware); /* Ensure period size is multiple of 8 */ ret = snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 0x8); if (ret) { dev_err(dev, "failed to set constraint %d\n", ret); kfree(prtd); return ret; } ret = snd_dmaengine_pcm_open_request_chan(substream, NULL, NULL); if (ret) { dev_err(dev, "dmaengine pcm open failed with err %d\n", ret); kfree(prtd); return ret; } snd_dmaengine_pcm_set_data(substream, prtd); return 0; }
static int tegra_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct tegra_runtime_data *prtd; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct tegra_pcm_dma_params * dmap; int ret = 0; prtd = kzalloc(sizeof(struct tegra_runtime_data), GFP_KERNEL); if (prtd == NULL) return -ENOMEM; init_timer(&prtd->pcm_timeout); prtd->callback_time = 0; runtime->private_data = prtd; prtd->substream = substream; spin_lock_init(&prtd->lock); dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if (dmap) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { setup_dma_tx_request(&prtd->dma_req[0], dmap); setup_dma_tx_request(&prtd->dma_req[1], dmap); } else { setup_dma_rx_request(&prtd->dma_req[0], dmap); setup_dma_rx_request(&prtd->dma_req[1], dmap); } prtd->dma_req[0].dev = prtd; prtd->dma_req[1].dev = prtd; prtd->dma_chan = tegra_dma_allocate_channel( TEGRA_DMA_MODE_CONTINUOUS_SINGLE, "pcm"); if (prtd->dma_chan == NULL) { ret = -ENOMEM; goto err; } } snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware); ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 0x8); if (ret < 0) goto err; ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) goto err; return 0; err: if (prtd->dma_chan) { tegra_dma_free_channel(prtd->dma_chan); } kfree(prtd); return ret; }
static int oxygen_open(struct snd_pcm_substream *substream, unsigned int channel) { struct oxygen *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err; runtime->private_data = (void *)(uintptr_t)channel; if (channel == PCM_B && chip->has_ac97_1 && (chip->model.device_config & CAPTURE_2_FROM_AC97_1)) runtime->hw = oxygen_ac97_hardware; else runtime->hw = *oxygen_hardware[channel]; switch (channel) { case PCM_C: runtime->hw.rates &= ~(SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_64000); runtime->hw.rate_min = 44100; break; case PCM_MULTICH: runtime->hw.channels_max = chip->model.dac_channels_pcm; break; } if (chip->model.pcm_hardware_filter) chip->model.pcm_hardware_filter(channel, &runtime->hw); err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); if (err < 0) return err; err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); if (err < 0) return err; if (runtime->hw.formats & SNDRV_PCM_FMTBIT_S32_LE) { err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); if (err < 0) return err; } if (runtime->hw.channels_max > 2) { err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2); if (err < 0) return err; } if (channel == PCM_MULTICH) { err = snd_pcm_hw_constraint_minmax (runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 0, 8192000); if (err < 0) return err; } snd_pcm_set_sync(substream); chip->streams[channel] = substream; mutex_lock(&chip->mutex); chip->pcm_active |= 1 << channel; if (channel == PCM_SPDIF) { chip->spdif_pcm_bits = chip->spdif_bits; chip->controls[CONTROL_SPDIF_PCM]->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, &chip->controls[CONTROL_SPDIF_PCM]->id); } mutex_unlock(&chip->mutex); return 0; }
/* open callback */ static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) { vortex_t *vortex = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err; /* Force equal size periods */ if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; /* Avoid PAGE_SIZE boundary to fall inside of a period. */ if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0) return err; snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 64); if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { #ifndef CHIP_AU8820 if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_A3D) { runtime->hw = snd_vortex_playback_hw_a3d; } #endif if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_SPDIF) { runtime->hw = snd_vortex_playback_hw_spdif; switch (vortex->spdif_sr) { case 32000: runtime->hw.rates = SNDRV_PCM_RATE_32000; break; case 44100: runtime->hw.rates = SNDRV_PCM_RATE_44100; break; case 48000: runtime->hw.rates = SNDRV_PCM_RATE_48000; break; } } if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB || VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_I2S) runtime->hw = snd_vortex_playback_hw_adb; #ifdef CHIP_AU8830 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && VORTEX_IS_QUAD(vortex) && VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { runtime->hw.channels_max = 4; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_au8830_channels); } #endif substream->runtime->private_data = NULL; } #ifndef CHIP_AU8810 else { runtime->hw = snd_vortex_playback_hw_wt; substream->runtime->private_data = NULL; } #endif return 0; }
static int pcm_init_hw_params(struct snd_bebob *bebob, struct snd_pcm_substream *substream) { int err; static const struct snd_pcm_hardware hw = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_FIFO_IN_FRAMES | SNDRV_PCM_INFO_JOINT_DUPLEX | /* for Open Sound System compatibility */ SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BLOCK_TRANSFER, /* set up later */ .rates = 0, .rate_min = UINT_MAX, .rate_max = 0, /* set up later */ .channels_min = UINT_MAX, .channels_max = 0, .buffer_bytes_max = 1024 * 1024 * 1024, .period_bytes_min = 256, .period_bytes_max = 1024 * 1024 * 1024 / 2, .periods_min = 2, .periods_max = 32, .fifo_size = 0, }; substream->runtime->hw = hw; substream->runtime->delay = substream->runtime->hw.fifo_size; /* add rule between channels and sampling rate */ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { prepare_rates(&substream->runtime->hw, bebob->tx_stream_formations); prepare_channels(&substream->runtime->hw, bebob->tx_stream_formations); substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE; snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, hw_rule_capture_channels, bebob, SNDRV_PCM_HW_PARAM_RATE, -1); snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, hw_rule_capture_rate, bebob, SNDRV_PCM_HW_PARAM_CHANNELS, -1); } else { prepare_rates(&substream->runtime->hw, bebob->rx_stream_formations); prepare_channels(&substream->runtime->hw, bebob->rx_stream_formations); substream->runtime->hw.formats = AMDTP_OUT_PCM_FORMAT_BITS; snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, hw_rule_playback_channels, bebob, SNDRV_PCM_HW_PARAM_RATE, -1); snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, hw_rule_playback_rate, bebob, SNDRV_PCM_HW_PARAM_CHANNELS, -1); } /* AM824 in IEC 61883-6 can deliver 24bit data */ err = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24); if (err < 0) goto end; /* * AMDTP functionality in firewire-lib require periods to be aligned to * 16 bit, or 24bit inner 32bit. */ err = snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); if (err < 0) goto end; /* time for period constraint */ err = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 500, UINT_MAX); if (err < 0) goto end; err = 0; end: return err; } static int pcm_open(struct snd_pcm_substream *substream) { struct snd_bebob *bebob = substream->private_data; struct snd_bebob_rate_spec *spec = bebob->spec->rate; unsigned int sampling_rate; bool internal; int err; err = snd_bebob_stream_lock_try(bebob); if (err < 0) goto end; err = pcm_init_hw_params(bebob, substream); if (err < 0) goto err_locked; err = snd_bebob_stream_check_internal_clock(bebob, &internal); if (err < 0) goto err_locked; /* * When source of clock is internal or any PCM stream are running, * the available sampling rate is limited at current sampling rate. */ if (!internal || amdtp_stream_pcm_running(&bebob->tx_stream) || amdtp_stream_pcm_running(&bebob->rx_stream)) { err = spec->get(bebob, &sampling_rate); if (err < 0) goto err_locked; substream->runtime->hw.rate_min = sampling_rate; substream->runtime->hw.rate_max = sampling_rate; } snd_pcm_set_sync(substream); end: return err; err_locked: snd_bebob_stream_lock_release(bebob); return err; } static int pcm_close(struct snd_pcm_substream *substream) { struct snd_bebob *bebob = substream->private_data; snd_bebob_stream_lock_release(bebob); return 0; } static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { return snd_pcm_lib_alloc_vmalloc_buffer(substream, params_buffer_bytes(hw_params)); } static int pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_bebob *bebob = substream->private_data; snd_bebob_stream_stop_duplex(bebob); return snd_pcm_lib_free_vmalloc_buffer(substream); } static int pcm_capture_prepare(struct snd_pcm_substream *substream) { struct snd_bebob *bebob = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; int err; err = snd_bebob_stream_start_duplex(bebob, &bebob->tx_stream, runtime->rate); if (err < 0) goto end; amdtp_stream_set_pcm_format(&bebob->tx_stream, runtime->format); amdtp_stream_pcm_prepare(&bebob->tx_stream); end: return err; } static int pcm_playback_prepare(struct snd_pcm_substream *substream) { struct snd_bebob *bebob = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; int err; err = snd_bebob_stream_start_duplex(bebob, &bebob->rx_stream, runtime->rate); if (err < 0) goto end; amdtp_stream_set_pcm_format(&bebob->rx_stream, runtime->format); amdtp_stream_pcm_prepare(&bebob->rx_stream); end: return err; } static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_bebob *bebob = substream->private_data; switch (cmd) { case SNDRV_PCM_TRIGGER_START: amdtp_stream_pcm_trigger(&bebob->tx_stream, substream); break; case SNDRV_PCM_TRIGGER_STOP: amdtp_stream_pcm_trigger(&bebob->tx_stream, NULL); break; default: return -EINVAL; } return 0; } static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_bebob *bebob = substream->private_data; switch (cmd) { case SNDRV_PCM_TRIGGER_START: amdtp_stream_pcm_trigger(&bebob->rx_stream, substream); break; case SNDRV_PCM_TRIGGER_STOP: amdtp_stream_pcm_trigger(&bebob->rx_stream, NULL); break; default: return -EINVAL; } return 0; } static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm) { struct snd_bebob *bebob = sbstrm->private_data; return amdtp_stream_pcm_pointer(&bebob->tx_stream); } static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) { struct snd_bebob *bebob = sbstrm->private_data; return amdtp_stream_pcm_pointer(&bebob->rx_stream); } static struct snd_pcm_ops pcm_capture_ops = { .open = pcm_open, .close = pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = pcm_hw_params, .hw_free = pcm_hw_free, .prepare = pcm_capture_prepare, .trigger = pcm_capture_trigger, .pointer = pcm_capture_pointer, .page = snd_pcm_lib_get_vmalloc_page, }; static struct snd_pcm_ops pcm_playback_ops = { .open = pcm_open, .close = pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = pcm_hw_params, .hw_free = pcm_hw_free, .prepare = pcm_playback_prepare, .trigger = pcm_playback_trigger, .pointer = pcm_playback_pointer, .page = snd_pcm_lib_get_vmalloc_page, .mmap = snd_pcm_lib_mmap_vmalloc, }; int snd_bebob_create_pcm_devices(struct snd_bebob *bebob) { struct snd_pcm *pcm; int err; err = snd_pcm_new(bebob->card, bebob->card->driver, 0, 1, 1, &pcm); if (err < 0) goto end; pcm->private_data = bebob; snprintf(pcm->name, sizeof(pcm->name), "%s PCM", bebob->card->shortname); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops); end: return err; }
static int tegra_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct tegra_runtime_data *prtd; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct tegra_pcm_dma_params * dmap; int ret = 0; prtd = kzalloc(sizeof(struct tegra_runtime_data), GFP_KERNEL); if (prtd == NULL) return -ENOMEM; runtime->private_data = prtd; prtd->substream = substream; spin_lock_init(&prtd->lock); dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if (dmap) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { setup_dma_tx_request(&prtd->dma_req[0], dmap); setup_dma_tx_request(&prtd->dma_req[1], dmap); } else { setup_dma_rx_request(&prtd->dma_req[0], dmap); setup_dma_rx_request(&prtd->dma_req[1], dmap); } prtd->dma_req[0].dev = prtd; prtd->dma_req[1].dev = prtd; prtd->dma_chan = tegra_dma_allocate_channel( TEGRA_DMA_MODE_CONTINUOUS_SINGLE, "pcm"); if (prtd->dma_chan == NULL) { ret = -ENOMEM; goto err; } } /* Set HW params now that initialization is complete */ snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware); /* Ensure period size is multiple of 8 */ ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 0x8); if (ret < 0) goto err; /* Ensure that buffer size is a multiple of period size */ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) goto err; #ifdef CONFIG_HAS_WAKELOCK snprintf(prtd->tegra_wake_lock_name, sizeof(prtd->tegra_wake_lock_name), "tegra-pcm-%s-%d", (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? "out" : "in", substream->pcm->device); wake_lock_init(&prtd->tegra_wake_lock, WAKE_LOCK_SUSPEND, prtd->tegra_wake_lock_name); #endif return 0; err: if (prtd->dma_chan) { tegra_dma_free_channel(prtd->dma_chan); } kfree(prtd); return ret; }
int snd_mixart_kill_ref_pipe(struct mixart_mgr *mgr, struct mixart_pipe *pipe, int monitoring) { int err = 0; if(pipe->status == PIPE_UNDEFINED) return 0; if(monitoring) pipe->monitoring = 0; else pipe->references--; if((pipe->references <= 0) && (pipe->monitoring == 0)) { struct mixart_msg request; struct mixart_delete_group_resp delete_resp; /* release the clock */ err = mixart_set_clock( mgr, pipe, 0); if( err < 0 ) { snd_printk(KERN_ERR "mixart_set_clock(0) return error!\n"); } /* stop the pipe */ err = mixart_set_pipe_state(mgr, pipe, 0); if( err < 0 ) { snd_printk(KERN_ERR "error stopping pipe!\n"); } request.message_id = MSG_STREAM_DELETE_GROUP; request.uid = (struct mixart_uid){0,0}; request.data = &pipe->group_uid; /* the streaming group ! */ request.size = sizeof(pipe->group_uid); /* delete the pipe */ err = snd_mixart_send_msg(mgr, &request, sizeof(delete_resp), &delete_resp); if ((err < 0) || (delete_resp.status != 0)) { snd_printk(KERN_ERR "error MSG_STREAM_DELETE_GROUP err(%x), status(%x)\n", err, delete_resp.status); } pipe->group_uid = (struct mixart_uid){0,0}; pipe->stream_count = 0; pipe->status = PIPE_UNDEFINED; } return err; } static int mixart_set_stream_state(struct mixart_stream *stream, int start) { struct snd_mixart *chip; struct mixart_stream_state_req stream_state_req; struct mixart_msg request; if(!stream->substream) return -EINVAL; memset(&stream_state_req, 0, sizeof(stream_state_req)); stream_state_req.stream_count = 1; stream_state_req.stream_info.stream_desc.uid_pipe = stream->pipe->group_uid; stream_state_req.stream_info.stream_desc.stream_idx = stream->substream->number; if (stream->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) request.message_id = start ? MSG_STREAM_START_INPUT_STAGE_PACKET : MSG_STREAM_STOP_INPUT_STAGE_PACKET; else request.message_id = start ? MSG_STREAM_START_OUTPUT_STAGE_PACKET : MSG_STREAM_STOP_OUTPUT_STAGE_PACKET; request.uid = (struct mixart_uid){0,0}; request.data = &stream_state_req; request.size = sizeof(stream_state_req); stream->abs_period_elapsed = 0; /* reset stream pos */ stream->buf_periods = 0; stream->buf_period_frag = 0; chip = snd_pcm_substream_chip(stream->substream); return snd_mixart_send_msg_nonblock(chip->mgr, &request); } /* * Trigger callback */ static int snd_mixart_trigger(struct snd_pcm_substream *subs, int cmd) { struct mixart_stream *stream = subs->runtime->private_data; switch (cmd) { case SNDRV_PCM_TRIGGER_START: snd_printdd("SNDRV_PCM_TRIGGER_START\n"); /* START_STREAM */ if( mixart_set_stream_state(stream, 1) ) return -EINVAL; stream->status = MIXART_STREAM_STATUS_RUNNING; break; case SNDRV_PCM_TRIGGER_STOP: /* STOP_STREAM */ if( mixart_set_stream_state(stream, 0) ) return -EINVAL; stream->status = MIXART_STREAM_STATUS_OPEN; snd_printdd("SNDRV_PCM_TRIGGER_STOP\n"); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* TODO */ stream->status = MIXART_STREAM_STATUS_PAUSE; snd_printdd("SNDRV_PCM_PAUSE_PUSH\n"); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* TODO */ stream->status = MIXART_STREAM_STATUS_RUNNING; snd_printdd("SNDRV_PCM_PAUSE_RELEASE\n"); break; default: return -EINVAL; } return 0; } static int mixart_sync_nonblock_events(struct mixart_mgr *mgr) { unsigned long timeout = jiffies + HZ; while (atomic_read(&mgr->msg_processed) > 0) { if (time_after(jiffies, timeout)) { snd_printk(KERN_ERR "mixart: cannot process nonblock events!\n"); return -EBUSY; } schedule_timeout_uninterruptible(1); } return 0; } /* * prepare callback for all pcms */ static int snd_mixart_prepare(struct snd_pcm_substream *subs) { struct snd_mixart *chip = snd_pcm_substream_chip(subs); struct mixart_stream *stream = subs->runtime->private_data; /* TODO de façon non bloquante, réappliquer les hw_params (rate, bits, codec) */ snd_printdd("snd_mixart_prepare\n"); mixart_sync_nonblock_events(chip->mgr); /* only the first stream can choose the sample rate */ /* the further opened streams will be limited to its frequency (see open) */ if(chip->mgr->ref_count_rate == 1) chip->mgr->sample_rate = subs->runtime->rate; /* set the clock only once (first stream) on the same pipe */ if(stream->pipe->references == 1) { if( mixart_set_clock(chip->mgr, stream->pipe, subs->runtime->rate) ) return -EINVAL; } return 0; } static int mixart_set_format(struct mixart_stream *stream, snd_pcm_format_t format) { int err; struct snd_mixart *chip; struct mixart_msg request; struct mixart_stream_param_desc stream_param; struct mixart_return_uid resp; chip = snd_pcm_substream_chip(stream->substream); memset(&stream_param, 0, sizeof(stream_param)); stream_param.coding_type = CT_LINEAR; stream_param.number_of_channel = stream->channels; stream_param.sampling_freq = chip->mgr->sample_rate; if(stream_param.sampling_freq == 0) stream_param.sampling_freq = 44100; /* if frequency not yet defined, use some default */ switch(format){ case SNDRV_PCM_FORMAT_U8: stream_param.sample_type = ST_INTEGER_8; stream_param.sample_size = 8; break; case SNDRV_PCM_FORMAT_S16_LE: stream_param.sample_type = ST_INTEGER_16LE; stream_param.sample_size = 16; break; case SNDRV_PCM_FORMAT_S16_BE: stream_param.sample_type = ST_INTEGER_16BE; stream_param.sample_size = 16; break; case SNDRV_PCM_FORMAT_S24_3LE: stream_param.sample_type = ST_INTEGER_24LE; stream_param.sample_size = 24; break; case SNDRV_PCM_FORMAT_S24_3BE: stream_param.sample_type = ST_INTEGER_24BE; stream_param.sample_size = 24; break; case SNDRV_PCM_FORMAT_FLOAT_LE: stream_param.sample_type = ST_FLOATING_POINT_32LE; stream_param.sample_size = 32; break; case SNDRV_PCM_FORMAT_FLOAT_BE: stream_param.sample_type = ST_FLOATING_POINT_32BE; stream_param.sample_size = 32; break; default: snd_printk(KERN_ERR "error mixart_set_format() : unknown format\n"); return -EINVAL; } snd_printdd("set SNDRV_PCM_FORMAT sample_type(%d) sample_size(%d) freq(%d) channels(%d)\n", stream_param.sample_type, stream_param.sample_size, stream_param.sampling_freq, stream->channels); /* TODO: what else to configure ? */ /* stream_param.samples_per_frame = 2; */ /* stream_param.bytes_per_frame = 4; */ /* stream_param.bytes_per_sample = 2; */ stream_param.pipe_count = 1; /* set to 1 */ stream_param.stream_count = 1; /* set to 1 */ stream_param.stream_desc[0].uid_pipe = stream->pipe->group_uid; stream_param.stream_desc[0].stream_idx = stream->substream->number; request.message_id = MSG_STREAM_SET_INPUT_STAGE_PARAM; request.uid = (struct mixart_uid){0,0}; request.data = &stream_param; request.size = sizeof(stream_param); err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp); if((err < 0) || resp.error_code) { snd_printk(KERN_ERR "MSG_STREAM_SET_INPUT_STAGE_PARAM err=%x; resp=%x\n", err, resp.error_code); return -EINVAL; } return 0; } /* * HW_PARAMS callback for all pcms */ static int snd_mixart_hw_params(struct snd_pcm_substream *subs, struct snd_pcm_hw_params *hw) { struct snd_mixart *chip = snd_pcm_substream_chip(subs); struct mixart_mgr *mgr = chip->mgr; struct mixart_stream *stream = subs->runtime->private_data; snd_pcm_format_t format; int err; int channels; /* set up channels */ channels = params_channels(hw); /* set up format for the stream */ format = params_format(hw); mutex_lock(&mgr->setup_mutex); /* update the stream levels */ if( stream->pcm_number <= MIXART_PCM_DIGITAL ) { int is_aes = stream->pcm_number > MIXART_PCM_ANALOG; if( subs->stream == SNDRV_PCM_STREAM_PLAYBACK ) mixart_update_playback_stream_level(chip, is_aes, subs->number); else mixart_update_capture_stream_level( chip, is_aes); } stream->channels = channels; /* set the format to the board */ err = mixart_set_format(stream, format); if(err < 0) { mutex_unlock(&mgr->setup_mutex); return err; } /* allocate buffer */ err = snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw)); if (err > 0) { struct mixart_bufferinfo *bufferinfo; int i = (chip->chip_idx * MIXART_MAX_STREAM_PER_CARD) + (stream->pcm_number * (MIXART_PLAYBACK_STREAMS+MIXART_CAPTURE_STREAMS)) + subs->number; if( subs->stream == SNDRV_PCM_STREAM_CAPTURE ) { i += MIXART_PLAYBACK_STREAMS; /* in array capture is behind playback */ } bufferinfo = (struct mixart_bufferinfo *)chip->mgr->bufferinfo.area; bufferinfo[i].buffer_address = subs->runtime->dma_addr; bufferinfo[i].available_length = subs->runtime->dma_bytes; /* bufferinfo[i].buffer_id is already defined */ snd_printdd("snd_mixart_hw_params(pcm %d) : dma_addr(%x) dma_bytes(%x) subs-number(%d)\n", i, bufferinfo[i].buffer_address, bufferinfo[i].available_length, subs->number); } mutex_unlock(&mgr->setup_mutex); return err; } static int snd_mixart_hw_free(struct snd_pcm_substream *subs) { struct snd_mixart *chip = snd_pcm_substream_chip(subs); snd_pcm_lib_free_pages(subs); mixart_sync_nonblock_events(chip->mgr); return 0; } /* * TODO CONFIGURATION SPACE for all pcms, mono pcm must update channels_max */ static struct snd_pcm_hardware snd_mixart_analog_caps = { .info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), .formats = ( SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE ), .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 8000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = (32*1024), .period_bytes_min = 256, /* 256 frames U8 mono*/ .period_bytes_max = (16*1024), .periods_min = 2, .periods_max = (32*1024/256), }; static struct snd_pcm_hardware snd_mixart_digital_caps = { .info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), .formats = ( SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE ), .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, .rate_min = 32000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = (32*1024), .period_bytes_min = 256, /* 256 frames U8 mono*/ .period_bytes_max = (16*1024), .periods_min = 2, .periods_max = (32*1024/256), }; static int snd_mixart_playback_open(struct snd_pcm_substream *subs) { struct snd_mixart *chip = snd_pcm_substream_chip(subs); struct mixart_mgr *mgr = chip->mgr; struct snd_pcm_runtime *runtime = subs->runtime; struct snd_pcm *pcm = subs->pcm; struct mixart_stream *stream; struct mixart_pipe *pipe; int err = 0; int pcm_number; mutex_lock(&mgr->setup_mutex); if ( pcm == chip->pcm ) { pcm_number = MIXART_PCM_ANALOG; runtime->hw = snd_mixart_analog_caps; } else { snd_BUG_ON(pcm != chip->pcm_dig); pcm_number = MIXART_PCM_DIGITAL; runtime->hw = snd_mixart_digital_caps; } snd_printdd("snd_mixart_playback_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number); /* get stream info */ stream = &(chip->playback_stream[pcm_number][subs->number]); if (stream->status != MIXART_STREAM_STATUS_FREE){ /* streams in use */ snd_printk(KERN_ERR "snd_mixart_playback_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number); err = -EBUSY; goto _exit_open; } /* get pipe pointer (out pipe) */ pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 0, 0); if (pipe == NULL) { err = -EINVAL; goto _exit_open; } /* start the pipe if necessary */ err = mixart_set_pipe_state(chip->mgr, pipe, 1); if( err < 0 ) { snd_printk(KERN_ERR "error starting pipe!\n"); snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0); err = -EINVAL; goto _exit_open; } stream->pipe = pipe; stream->pcm_number = pcm_number; stream->status = MIXART_STREAM_STATUS_OPEN; stream->substream = subs; stream->channels = 0; /* not configured yet */ runtime->private_data = stream; snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 64); /* if a sample rate is already used, another stream cannot change */ if(mgr->ref_count_rate++) { if(mgr->sample_rate) { runtime->hw.rate_min = runtime->hw.rate_max = mgr->sample_rate; } } _exit_open: mutex_unlock(&mgr->setup_mutex); return err; } static int snd_mixart_capture_open(struct snd_pcm_substream *subs) { struct snd_mixart *chip = snd_pcm_substream_chip(subs); struct mixart_mgr *mgr = chip->mgr; struct snd_pcm_runtime *runtime = subs->runtime; struct snd_pcm *pcm = subs->pcm; struct mixart_stream *stream; struct mixart_pipe *pipe; int err = 0; int pcm_number; mutex_lock(&mgr->setup_mutex); if ( pcm == chip->pcm ) { pcm_number = MIXART_PCM_ANALOG; runtime->hw = snd_mixart_analog_caps; } else { snd_BUG_ON(pcm != chip->pcm_dig); pcm_number = MIXART_PCM_DIGITAL; runtime->hw = snd_mixart_digital_caps; } runtime->hw.channels_min = 2; /* for instance, no mono */ snd_printdd("snd_mixart_capture_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number); /* get stream info */ stream = &(chip->capture_stream[pcm_number]); if (stream->status != MIXART_STREAM_STATUS_FREE){ /* streams in use */ snd_printk(KERN_ERR "snd_mixart_capture_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number); err = -EBUSY; goto _exit_open; } /* get pipe pointer (in pipe) */ pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 1, 0); if (pipe == NULL) { err = -EINVAL; goto _exit_open; } /* start the pipe if necessary */ err = mixart_set_pipe_state(chip->mgr, pipe, 1); if( err < 0 ) { snd_printk(KERN_ERR "error starting pipe!\n"); snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0); err = -EINVAL; goto _exit_open; } stream->pipe = pipe; stream->pcm_number = pcm_number; stream->status = MIXART_STREAM_STATUS_OPEN; stream->substream = subs; stream->channels = 0; /* not configured yet */ runtime->private_data = stream; snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 64); /* if a sample rate is already used, another stream cannot change */ if(mgr->ref_count_rate++) { if(mgr->sample_rate) { runtime->hw.rate_min = runtime->hw.rate_max = mgr->sample_rate; } } _exit_open: mutex_unlock(&mgr->setup_mutex); return err; } static int snd_mixart_close(struct snd_pcm_substream *subs) { struct snd_mixart *chip = snd_pcm_substream_chip(subs); struct mixart_mgr *mgr = chip->mgr; struct mixart_stream *stream = subs->runtime->private_data; mutex_lock(&mgr->setup_mutex); snd_printdd("snd_mixart_close C%d/P%d/Sub%d\n", chip->chip_idx, stream->pcm_number, subs->number); /* sample rate released */ if(--mgr->ref_count_rate == 0) { mgr->sample_rate = 0; } /* delete pipe */ if (snd_mixart_kill_ref_pipe(mgr, stream->pipe, 0 ) < 0) { snd_printk(KERN_ERR "error snd_mixart_kill_ref_pipe C%dP%d\n", chip->chip_idx, stream->pcm_number); } stream->pipe = NULL; stream->status = MIXART_STREAM_STATUS_FREE; stream->substream = NULL; mutex_unlock(&mgr->setup_mutex); return 0; } static snd_pcm_uframes_t snd_mixart_stream_pointer(struct snd_pcm_substream *subs) { struct snd_pcm_runtime *runtime = subs->runtime; struct mixart_stream *stream = runtime->private_data; return (snd_pcm_uframes_t)((stream->buf_periods * runtime->period_size) + stream->buf_period_frag); } static struct snd_pcm_ops snd_mixart_playback_ops = { .open = snd_mixart_playback_open, .close = snd_mixart_close, .ioctl = snd_pcm_lib_ioctl, .prepare = snd_mixart_prepare, .hw_params = snd_mixart_hw_params, .hw_free = snd_mixart_hw_free, .trigger = snd_mixart_trigger, .pointer = snd_mixart_stream_pointer, }; static struct snd_pcm_ops snd_mixart_capture_ops = { .open = snd_mixart_capture_open, .close = snd_mixart_close, .ioctl = snd_pcm_lib_ioctl, .prepare = snd_mixart_prepare, .hw_params = snd_mixart_hw_params, .hw_free = snd_mixart_hw_free, .trigger = snd_mixart_trigger, .pointer = snd_mixart_stream_pointer, }; static void preallocate_buffers(struct snd_mixart *chip, struct snd_pcm *pcm) { #if 0 struct snd_pcm_substream *subs; int stream; for (stream = 0; stream < 2; stream++) { int idx = 0; for (subs = pcm->streams[stream].substream; subs; subs = subs->next, idx++) /* set up the unique device id with the chip index */ subs->dma_device.id = subs->pcm->device << 16 | subs->stream << 8 | (subs->number + 1) | (chip->chip_idx + 1) << 24; } #endif snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->mgr->pci), 32*1024, 32*1024); } /* */ static int snd_mixart_pcm_analog(struct snd_mixart *chip) { int err; struct snd_pcm *pcm; char name[32]; sprintf(name, "miXart analog %d", chip->chip_idx); if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_ANALOG, MIXART_PLAYBACK_STREAMS, MIXART_CAPTURE_STREAMS, &pcm)) < 0) { snd_printk(KERN_ERR "cannot create the analog pcm %d\n", chip->chip_idx); return err; } pcm->private_data = chip; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_mixart_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops); pcm->info_flags = 0; strcpy(pcm->name, name); preallocate_buffers(chip, pcm); chip->pcm = pcm; return 0; } /* */ static int snd_mixart_pcm_digital(struct snd_mixart *chip) { int err; struct snd_pcm *pcm; char name[32]; sprintf(name, "miXart AES/EBU %d", chip->chip_idx); if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_DIGITAL, MIXART_PLAYBACK_STREAMS, MIXART_CAPTURE_STREAMS, &pcm)) < 0) { snd_printk(KERN_ERR "cannot create the digital pcm %d\n", chip->chip_idx); return err; } pcm->private_data = chip; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_mixart_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops); pcm->info_flags = 0; strcpy(pcm->name, name); preallocate_buffers(chip, pcm); chip->pcm_dig = pcm; return 0; } static int snd_mixart_chip_free(struct snd_mixart *chip) { kfree(chip); return 0; } static int snd_mixart_chip_dev_free(struct snd_device *device) { struct snd_mixart *chip = device->device_data; return snd_mixart_chip_free(chip); } /* */ static int __devinit snd_mixart_create(struct mixart_mgr *mgr, struct snd_card *card, int idx) { int err; struct snd_mixart *chip; static struct snd_device_ops ops = { .dev_free = snd_mixart_chip_dev_free, }; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (! chip) { snd_printk(KERN_ERR "cannot allocate chip\n"); return -ENOMEM; } chip->card = card; chip->chip_idx = idx; chip->mgr = mgr; if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_mixart_chip_free(chip); return err; } mgr->chip[idx] = chip; snd_card_set_dev(card, &mgr->pci->dev); return 0; }
/** * fsl_ssi_startup: create a new substream * * This is the first function called when a stream is opened. * * If this is the first stream open, then grab the IRQ and program most of * the SSI registers. */ static int fsl_ssi_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai); int synchronous = ssi_private->cpu_dai_drv.symmetric_rates; unsigned long flags; if (ssi_private->ssi_on_imx) { pm_runtime_get_sync(dai->dev); clk_prepare_enable(ssi_private->coreclk); clk_prepare_enable(ssi_private->clk); /* When using dual fifo mode, it would be safer if we ensure * its period size to be an even number. If appearing to an * odd number, the 2nd fifo might be neglected by SDMA sciprt * at the end of each period. */ if (ssi_private->use_dual_fifo) snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2); } /* * If this is the first stream opened, then request the IRQ * and initialize the SSI registers. */ if (!dai->active) { struct ccsr_ssi __iomem *ssi = ssi_private->ssi; /* * Section 16.5 of the MPC8610 reference manual says that the * SSI needs to be disabled before updating the registers we set * here. */ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0); /* * Program the SSI into I2S Slave Non-Network Synchronous mode. * Also enable the transmit and receive FIFO. * * FIXME: Little-endian samples require a different shift dir */ ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE; write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN, CCSR_SSI_SCR_TFR_CLK_DIS | ssi_private->i2s_mode | (synchronous ? CCSR_SSI_SCR_SYN : 0)); write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 | CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS | CCSR_SSI_STCR_TSCKP, &ssi->stcr); write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 | CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS | CCSR_SSI_SRCR_RSCKP, &ssi->srcr); /* * The DC and PM bits are only used if the SSI is the clock * master. */ /* Enable the interrupts and DMA requests */ write_ssi(SIER_FLAGS, &ssi->sier); /* * Set the watermark for transmit FIFI 0 and receive FIFO 0. We * don't use FIFO 1. We program the transmit water to signal a * DMA transfer if there are only two (or fewer) elements left * in the FIFO. Two elements equals one frame (left channel, * right channel). This value, however, depends on the depth of * the transmit buffer. * * We program the receive FIFO to notify us if at least two * elements (one frame) have been written to the FIFO. We could * make this value larger (and maybe we should), but this way * data will be written to memory as soon as it's available. */ write_ssi(CCSR_SSI_SFCSR_TFWM0(ssi_private->fifo_depth - 2) | CCSR_SSI_SFCSR_RFWM0(ssi_private->fifo_depth - 2) | CCSR_SSI_SFCSR_TFWM1(ssi_private->fifo_depth - 2) | CCSR_SSI_SFCSR_RFWM1(ssi_private->fifo_depth - 2), &ssi->sfcsr); /* Select Single/Dual fifo mode */ if (ssi_private->use_dual_fifo) { write_ssi_mask(&ssi->srcr, 0, CCSR_SSI_SRCR_RFEN1); write_ssi_mask(&ssi->stcr, 0, CCSR_SSI_STCR_TFEN1); write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_TCH_EN); } else { write_ssi_mask(&ssi->srcr, CCSR_SSI_SRCR_RFEN1, 0); write_ssi_mask(&ssi->stcr, CCSR_SSI_STCR_TFEN1, 0); write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TCH_EN, 0); } /* * We keep the SSI disabled because if we enable it, then the * DMA controller will start. It's not supposed to start until * the SCR.TE (or SCR.RE) bit is set, but it does anyway. The * DMA controller will transfer one "BWC" of data (i.e. the * amount of data that the MR.BWC bits are set to). The reason * this is bad is because at this point, the PCM driver has not * finished initializing the DMA controller. */ /* Set default slot number -- 2 */ write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_DC_MASK, CCSR_SSI_SxCCR_DC(2)); write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_DC_MASK, CCSR_SSI_SxCCR_DC(2)); spin_lock_irqsave(&ssi_private->baudclk_lock, flags); ssi_private->baudclk_locked = false; spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags); } return 0; }