Ejemplo n.º 1
0
static void __devexit intel_mid_i2s_remove(struct pci_dev *pdev)
{
	struct intel_mid_i2s_hdl *drv_data;

	pm_runtime_get_noresume(&pdev->dev);
	pm_runtime_forbid(&pdev->dev);

	drv_data = pci_get_drvdata(pdev);
	if (!drv_data) {
		dev_err(&pdev->dev, "no drv_data in pci device to remove!\n");
		goto leave;
	}
	if (test_bit(I2S_PORT_OPENED, &drv_data->flags)) {
		dev_warn(&pdev->dev, "Not closed before removing pci_dev!\n");
		intel_mid_i2s_close(drv_data);
	}
	pci_set_drvdata(pdev, NULL);
	/* Stop DMA is already done during close()  */
	pci_dev_put(drv_data->dmac1);
	/* Disable the SSP at the peripheral and SOC level */
	write_SSCR0(0, drv_data->ioaddr);
	free_irq(drv_data->irq, drv_data);
	iounmap(drv_data->ioaddr);
	pci_release_region(pdev, MRST_SSP_BAR);
	pci_release_region(pdev, MRST_LPE_BAR);
	pci_disable_device(pdev);
	kfree(drv_data);
leave:
	return;
}
static int ssp_test_release(struct inode *inode, struct file *file)
{
	DENTER();

	spin_lock_bh(&ssp_test_driver_data.lock);
	ssp_test_driver_data.opened = 0;
	ssp_test_driver_data.written = 0;
	spin_unlock_bh(&ssp_test_driver_data.lock);

	/* Set the Read Callback */
	intel_mid_i2s_set_rd_cb(handle_ssp1, NULL);
	/* Set the Write Callback */
	intel_mid_i2s_set_wr_cb(handle_ssp1, NULL);

	/* Free SSP reserved DMA channel */
	if (ssp_test_driver_data.tx_dma_chnl_allocated) {
		intel_mid_i2s_command(handle_ssp1, SSP_CMD_FREE_TX, NULL);
		ssp_test_driver_data.tx_dma_chnl_allocated = 0;
	}
	if (ssp_test_driver_data.rx_dma_chnl_allocated) {
		intel_mid_i2s_command(handle_ssp1, SSP_CMD_FREE_RX, NULL);
		ssp_test_driver_data.rx_dma_chnl_allocated = 0;
	}

	dev_dbg(TEST_DEV, "FCT %s DMA Channels released\n", __func__);

	/* order 1 => 4K requested */
	free_slots_buf_dma(&ssp_test_driver_data.rx, BUFSIZE_ORDER);
	free_slots_buf_dma(&ssp_test_driver_data.tx, BUFSIZE_ORDER);

	/* we can close the ssp */
	intel_mid_i2s_close(handle_ssp1);
	handle_ssp1 = NULL;

	DLEAVE(0);
	return 0;
}
Ejemplo n.º 3
0
static void ssp_dai_shutdown(struct snd_pcm_substream *substream,
			     struct snd_soc_dai *cpu_dai)
{
	struct intel_ssp_config *ssp_config;
	struct intel_alsa_ssp_stream_info *str_info;
	struct snd_pcm_runtime *runtime;

	ssp_config = snd_soc_dai_get_dma_data(cpu_dai, substream);

	BUG_ON(!ssp_config);

	switch (substream->stream) {
	case SNDRV_PCM_STREAM_PLAYBACK:
		/*
		 * Only Free Tx channel if no playback streams are active
		 * Shutdown can be called right after a startup if something
		 * failed (as a concurrency issue
		 * so this case can happen
		 */
		if ((!cpu_dai->playback_active) &&
			(ssp_config->i2s_settings.ssp_active_tx_slots_map)) {
			intel_mid_i2s_command(ssp_config->i2s_handle,
					SSP_CMD_FREE_TX, NULL);
			pr_debug("SSP DAI: FCT %s TX DMA Channel released\n",
					__func__);
		}
		break;

	case SNDRV_PCM_STREAM_CAPTURE:
		/*
		 * Only Free Rx channel if no capture streams are active
		 */
		if ((!cpu_dai->capture_active) &&
			(ssp_config->i2s_settings.ssp_active_rx_slots_map)) {
			intel_mid_i2s_command(ssp_config->i2s_handle,
					SSP_CMD_FREE_RX, NULL);
			pr_debug("SSP DAI: FCT %s RX DMA Channel released\n",
					__func__);
		}
		break;

	default:
		pr_err("SSP DAI: FCT %s Bad stream_dir: %d\n",
				__func__, substream->stream);
		break;
	}

	runtime = substream->runtime;
	str_info = runtime->private_data;

	/* Cancel pending work */
	cancel_work_sync(&str_info->ssp_ws);

	kfree(str_info);

	if (!cpu_dai->active) {
		pr_info("SSP DAI: FCT %s closing I2S\n",
				__func__);
		/*
		 * Close the Intel MID I2S connection
		 */
		intel_mid_i2s_close(ssp_config->i2s_handle);

		ssp_config->i2s_handle = NULL;
		ssp_config->intel_mid_dma_alloc = false;
	}

} /* ssp_dai_shutdown */
/*
 * intel_alsa_ssp_close - This function closes the requested stream
 * The Intel I2S driver is closed only if all streams are closed
 *
 * Input parameters
 *		@str_info : pointer to stream structure
 * Output parameters
 *		@ret_val : status
 */
static int intel_alsa_ssp_close(struct intel_alsa_ssp_stream_info *str_info)
{
	unsigned int device_id;
	bool close_ssp = false;

	WARN(!str_info, "ALSA_SSP: NULL str_info\n");
	if (!str_info)
		return -EINVAL;

	WARN(!s_stream_status.ssp_handle, "ALSA_SSP: ERROR, trying to close  "
					"a stream however ssp_handle is NULL\n");
	if (!s_stream_status.ssp_handle)
		return -EINVAL;

	device_id = str_info->device_id;

	/* Algorithm that detects conflicting call of open /close*/
	spin_lock(&s_stream_status.lock);

	if (s_stream_status.stream_info == 0) {
		spin_unlock(&s_stream_status.lock);
		WARN(1, "ALSA SSP: Close before Open\n");
		return -EBUSY;
	}

	clear_bit(str_info->stream_index, &s_stream_status.stream_info);

	if (s_stream_status.stream_info == 0)
		close_ssp = true;

	spin_unlock(&s_stream_status.lock);

	/*
	 * Release the DMA Channels
	 */

	switch (str_info->substream->stream) {

	case SNDRV_PCM_STREAM_PLAYBACK:
		intel_mid_i2s_command(s_stream_status.ssp_handle,
				SSP_CMD_FREE_TX, NULL);

		pr_debug("ALSA SSP: FCT %s TX DMA Channel released\n",
				__func__);
		break;

	case SNDRV_PCM_STREAM_CAPTURE:
		intel_mid_i2s_command(s_stream_status.ssp_handle,
				SSP_CMD_FREE_RX, NULL);
		pr_debug("ALSA SSP: FCT %s RX DMA Channel released\n",
				__func__);
		break;

	default:
		WARN(1, "ALSA SSP: FCT %s Bad stream_dir: %d\n",
				__func__, str_info->substream->stream);
		spin_unlock(&s_stream_status.lock);
		return -EINVAL;
		break;
	}

	/*
	 * the Close SSP is performed out of lock
	 */
	if (close_ssp) {
		intel_mid_i2s_close(s_stream_status.ssp_handle);
		s_stream_status.ssp_handle = NULL;
	}

	return 0;
} /* intel_alsa_ssp_close */