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; }
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 */