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; }
/** * intel_mid_i2s_close - release and stop the SSP * @drv_data : handle of corresponding ssp i2s (given by i2s_open function) * * WARNING: This is not -yet- allowed to call close from a read/write callback ! * * Output parameters * none */ void intel_mid_i2s_close(struct intel_mid_i2s_hdl *drv_data) { void __iomem *reg; struct intel_mid_i2s_settings *ssp_settings = &(drv_data->current_settings); int s; struct dma_chan *channel; WARN(!drv_data, "Driver data=NULL\n"); if (!drv_data) return; mutex_lock(&drv_data->mutex); if (!test_bit(I2S_PORT_OPENED, &drv_data->flags)) { dev_err(&drv_data->pdev->dev, "not opened but closing?"); mutex_unlock(&drv_data->mutex); return; } set_bit(I2S_PORT_CLOSING, &drv_data->flags); dev_info(&drv_data->pdev->dev, "Status bit pending write=%d read=%d\n", test_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags), test_bit(I2S_PORT_READ_BUSY, &drv_data->flags)); if (test_bit(I2S_PORT_WRITE_BUSY, &drv_data->flags) || test_bit(I2S_PORT_READ_BUSY, &drv_data->flags)) { dev_info(&drv_data->pdev->dev, "Pending callback in close...\n"); } if (ssp_settings->ssp_active_tx_slots_map) { channel = drv_data->txchan; s = channel->device->device_control(channel, DMA_TERMINATE_ALL, 0); dev_info(&drv_data->pdev->dev, "DMA_TERMINATE tx=%d\n", s); } if (ssp_settings->ssp_active_rx_slots_map) { channel = drv_data->rxchan; s = channel->device->device_control(channel, DMA_TERMINATE_ALL, 0); dev_info(&drv_data->pdev->dev, "DMA_TERMINATE rx=%d\n", s); } /* release DMA Channel.. */ i2s_dma_stop(drv_data); reg = drv_data->ioaddr; dev_dbg(&drv_data->pdev->dev, "Stopping the SSP\n"); i2s_ssp_stop(drv_data); put_device(&drv_data->pdev->dev); write_SSCR0(0, reg); dev_dbg(&(drv_data->pdev->dev), "SSP Stopped.\n"); clear_bit(I2S_PORT_CLOSING, &drv_data->flags); clear_bit(I2S_PORT_OPENED, &drv_data->flags); /* pm runtime */ pm_runtime_put(&drv_data->pdev->dev); mutex_unlock(&drv_data->mutex); }
/* * set_ssp_i2s_hw - Configure SSP driver according to settings. * @regs: pointer to registers * @shim: pointer to shim registers * @settings: config settings * @bps: bits per sample * * Configure SSP driver according to settings. */ static void set_ssp_i2s_hw(AplI2sRegs *regs, AplI2sRegs *shim, const AplI2sSettings *settings, int bps) { uint32_t sscr0; uint32_t sscr1; uint32_t sscr2; uint32_t sscr3; uint32_t sstsa; uint32_t ssrsa; uint32_t sspsp; uint32_t sspsp2 = 0; uint32_t sssr = 0; uint32_t ssioc; sscr0 = calculate_sscr0(settings, bps); sscr1 = calculate_sscr1(settings); sscr2 = calculate_sscr2(); sscr3 = 0; sspsp = calculate_sspsp(settings); sstsa = SSTSA_reg(TTSA, settings->ssp_active_tx_slots_map); ssrsa = SSRSA_reg(RTSA, settings->ssp_active_rx_slots_map); ssioc = calculate_ssioc(); write_SSCR0(sscr0, regs); write_SSCR1(sscr1, regs); write_SSCR2(sscr2, regs); write_SSCR3(sscr3, regs); write_SSPSP(sspsp, regs); write_SSPSP2(sspsp2, regs); write_SSTSA(sstsa, regs); write_SSRSA(ssrsa, regs); write_SSIOC(ssioc, regs); /* Clear status */ write_SSSR(sssr, regs); /* set the time out for the reception */ write_SSTO(SSP_TIMEOUT, regs); }
static void pxa2xx_spi_dma_error_stop(struct driver_data *drv_data, const char *msg) { void __iomem *reg = drv_data->ioaddr; /* Stop and reset */ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; write_SSSR_CS(drv_data, drv_data->clear_sr); write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); if (!pxa25x_ssp_comp(drv_data)) write_SSTO(0, reg); pxa2xx_spi_flush(drv_data); write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); pxa2xx_spi_unmap_dma_buffers(drv_data); dev_err(&drv_data->pdev->dev, "%s\n", msg); drv_data->cur_msg->state = ERROR_STATE; tasklet_schedule(&drv_data->pump_transfers); }
/** * set_ssp_i2s_hw - configure the SSP driver according to the ps_settings * @drv_data : structure that contains all details about the SSP Driver * @ps_settings : structure that contains SSP Hardware settings * * it also store ps_settings the drv_data * * Output parameters * NA */ static void set_ssp_i2s_hw(struct intel_mid_i2s_hdl *drv_data, const struct intel_mid_i2s_settings *ps_settings) { u32 sscr0 = 0; u32 sscr1 = 0; u32 sstsa = 0; u32 ssrsa = 0; u32 sspsp = 0; u32 sssr = 0; /* Get the SSP Settings */ u16 l_ssp_clk_frm_mode = 0xFF; void __iomem *reg = drv_data->ioaddr; struct device *ddbg = &(drv_data->pdev->dev); dev_dbg(ddbg, "setup SSP I2S PCM1 configuration\n"); if ((ps_settings->sspsfrm_direction == SSPSFRM_MASTER_MODE) && (ps_settings->sspslclk_direction == SSPSCLK_MASTER_MODE)) { l_ssp_clk_frm_mode = SSP_IN_MASTER_MODE; } else if ((ps_settings->sspsfrm_direction == SSPSFRM_SLAVE_MODE) && (ps_settings->sspslclk_direction == SSPSCLK_SLAVE_MODE)) { l_ssp_clk_frm_mode = SSP_IN_SLAVE_MODE; } else { dev_err(ddbg, "Unsupported I2S PCM1 configuration\n"); goto leave; } dev_dbg(ddbg, "SSPSFRM_DIRECTION:%d:\n", ps_settings->sspsfrm_direction); dev_dbg(ddbg, "SSPSCLK_DIRECTION:%d:\n", ps_settings->sspslclk_direction); if (ps_settings->frame_format != PSP_FORMAT) { dev_err(ddbg, "UNSUPPORTED FRAME FORMAT:%d:\n", ps_settings->frame_format); goto leave; } if ((ps_settings->ssp_tx_dma != SSP_TX_DMA_ENABLE) || (ps_settings->ssp_rx_dma != SSP_RX_DMA_ENABLE)) { dev_err(ddbg, "ONLY DMA MODE IS SUPPORTED"); goto leave; } /*********** DMA Transfer Mode ***********/ dev_dbg(ddbg, "FORMAT :%d:\n", ps_settings->frame_format); sscr0 = calculate_sscr0_psp(ps_settings); dev_dbg(ddbg, " sscr0 :0x%08X\n", sscr0); sscr1 = calculate_sscr1_psp(ps_settings); dev_dbg(ddbg, " sscr1 :0x%08X\n", sscr1); if (ps_settings->mode == SSP_IN_NETWORK_MODE) { dev_dbg(ddbg, "MODE :%d:\n", ps_settings->mode); sscr0 |= SSCR0_reg(FRDC, SSCR0_SlotsPerFrm(ps_settings-> frame_rate_divider_control)); dev_dbg(ddbg, "sscr0 :0x%08X\n", sscr0); sspsp = calculate_sspsp_psp(ps_settings); dev_dbg(ddbg, "sspsp :0x%08X\n", sspsp); /* set the active TX time slot (bitmap) */ sstsa = SSTSA_reg(TTSA, ps_settings->ssp_active_tx_slots_map); /* set the active RX time slot (bitmap) */ ssrsa = SSRSA_reg(RTSA, ps_settings->ssp_active_rx_slots_map); if (l_ssp_clk_frm_mode == SSP_IN_MASTER_MODE) { switch (ps_settings->master_mode_clk_selection) { case SSP_ONCHIP_CLOCK: break; case SSP_NETWORK_CLOCK: sscr0 |= SSCR0_reg(NCS, 1); break; case SSP_EXTERNAL_CLOCK: sscr0 |= SSCR0_reg(ECS, 1); break; case SSP_ONCHIP_AUDIO_CLOCK: sscr0 |= SSCR0_reg(ACS, 1); break; default: dev_err(ddbg, "Master Mode clk selection UNKNOWN"); break; } sspsp |= SSPSP_reg(STRTDLY, ps_settings->ssp_psp_T1) |SSPSP_reg(DMYSTRT, ps_settings->ssp_psp_T2); } else { /* Set the Slave Clock Free Running Status */ sscr1 |= SSCR1_reg(SCFR, ps_settings->slave_clk_free_running_status); } } else { /* SSP_IN_NORMAL_MODE */ dev_err(ddbg, "UNSUPPORTED MODE"); goto leave; } /* Clear status */ sssr = (SSSR_BCE_MASK << SSSR_BCE_SHIFT) | (SSSR_TUR_MASK << SSSR_TUR_SHIFT) | (SSSR_TINT_MASK << SSSR_TINT_SHIFT) | (SSSR_PINT_MASK << SSSR_PINT_SHIFT) | (SSSR_ROR_MASK << SSSR_ROR_SHIFT); /* disable SSP */ clear_SSCR0_reg(reg, SSE); dev_dbg(ddbg, "WRITE SSCR0 DISABLE\n"); /* Clear status */ write_SSSR(sssr, reg); dev_dbg(ddbg, "WRITE SSSR: 0x%08X\n", sssr); write_SSCR0(sscr0, reg); dev_dbg(ddbg, "WRITE SSCR0\n"); /* first set CR1 without interrupt and service enables */ write_SSCR1(sscr1, reg); write_SSPSP(sspsp, reg); write_SSTSA(sstsa, reg); write_SSRSA(ssrsa, reg); /* set the time out for the reception */ write_SSTO(0, reg); ssp1_dump_registers(drv_data); leave: return; }