irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data) { u32 irq_status; void __iomem *reg = drv_data->ioaddr; irq_status = read_SSSR(reg) & drv_data->mask_sr; if (irq_status & SSSR_ROR) { pxa2xx_spi_dma_error_stop(drv_data, "dma_transfer: fifo overrun"); return IRQ_HANDLED; } /* Check for false positive timeout */ if ((irq_status & SSSR_TINT) && (DCSR(drv_data->tx_channel) & DCSR_RUN)) { write_SSSR(SSSR_TINT, reg); return IRQ_HANDLED; } if (irq_status & SSSR_TINT || drv_data->rx == drv_data->rx_end) { /* Clear and disable timeout interrupt, do the rest in * dma_transfer_complete */ if (!pxa25x_ssp_comp(drv_data)) write_SSTO(0, reg); /* finish this transfer, start the next */ pxa2xx_spi_dma_transfer_complete(drv_data); return IRQ_HANDLED; } /* Opps problem detected */ return IRQ_NONE; }
static void cs_assert(struct driver_data *drv_data) { struct chip_data *chip = drv_data->cur_chip; if (drv_data->ssp_type == CE4100_SSP) { write_SSSR(drv_data->cur_chip->frm, drv_data->ioaddr); return; } if (chip->cs_control) { chip->cs_control(PXA2XX_CS_ASSERT); return; } if (gpio_is_valid(chip->gpio_cs)) { gpio_set_value(chip->gpio_cs, chip->gpio_cs_inverted); return; } if (drv_data->ssp_type == INTEL_SSP) { write_SSFS((1 << chip->chip_select), drv_data->ioaddr); return; } lpss_ssp_cs_control(drv_data, true); }
static void write_SSSR_CS(struct driver_data *drv_data, u32 val) { void __iomem *reg = drv_data->ioaddr; if (drv_data->ssp_type == CE4100_SSP) val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK; write_SSSR(val, reg); }
static int flush(struct driver_data *drv_data) { unsigned long limit = loops_per_jiffy << 1; void __iomem *reg = drv_data->ioaddr; do { while (read_SSSR(reg) & SSSR_RNE) { read_SSDR(reg); } } while ((read_SSSR(reg) & SSSR_BSY) && limit--); write_SSSR(SSSR_ROR, reg); return limit; }
/* * 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); }
/** * 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; }
/** * i2s_int(): function that handles the SSP Interrupts (errors) * @irq : IRQ Number * @dev_id : structure that contains driver information * * This interrupts do nothing but warnings in case there is some problems * in I2S connection (underruns, overruns...). This may be reported by adding a * new interface to the driver, but not yet requested by "users" of this driver * * Output parameters * NA */ static irqreturn_t i2s_int(int irq, void *dev_id) { struct intel_mid_i2s_hdl *drv_data = dev_id; void __iomem *reg; u32 irq_status = 0; u32 mask_status = 0; struct device *ddbg = &(drv_data->pdev->dev); if (drv_data->in_suspend) return IRQ_NONE; #ifdef CONFIG_PM_RUNTIME if (pm_runtime_suspended(ddbg)) return IRQ_NONE; #endif reg = drv_data->ioaddr; irq_status = read_SSSR(reg); if (!(irq_status & (drv_data->mask_sr))) { return IRQ_NONE; } else { /* may be improved by using a tasklet to send the error * (underrun,...) to client by using callback */ if (irq_status & (SSSR_ROR_MASK << SSSR_ROR_SHIFT)) { dev_warn(ddbg, "ssp_int RX FIFO OVER RUN SSSR=0x%08X\n", irq_status); mask_status |= (SSSR_ROR_MASK << SSSR_ROR_SHIFT); } if (irq_status & (SSSR_TUR_MASK << SSSR_TUR_SHIFT)) { dev_warn(ddbg, "ssp_int TX FIFO UNDER RUN SSSR=0x%08X\n", irq_status); mask_status |= (SSSR_TUR_MASK << SSSR_TUR_SHIFT); } if (irq_status & (SSSR_TINT_MASK << SSSR_TINT_SHIFT)) { dev_warn(ddbg, "ssp_int RX TIME OUT SSSR=0x%08X\n", irq_status); mask_status |= (SSSR_TINT_MASK << SSSR_TINT_SHIFT); } if (irq_status & (SSSR_PINT_MASK << SSSR_PINT_SHIFT)) { dev_warn(ddbg, "ssp_int TRAILING BYTE SSSR=0x%08X\n", irq_status); mask_status |= (SSSR_PINT_MASK << SSSR_PINT_SHIFT); } if (irq_status & (SSSR_EOC_MASK << SSSR_EOC_SHIFT)) { dev_warn(ddbg, "ssp_int END OF CHAIN SSSR=0x%08X\n", irq_status); mask_status |= (SSSR_EOC_MASK << SSSR_EOC_SHIFT); } /* clear sticky bits */ write_SSSR((irq_status & mask_status), reg); } return IRQ_HANDLED; }