/** * intel_mid_i2s_flush - This is the I2S flush request * @drv_data : pointer on private i2s driver data (by i2s_open function) * * It will flush the TX FIFO * WARNING: this function is used in a Burst Mode context where it is called * between Bursts i.e. when there is no FMSYNC, no transfer ongoing at * that time * If you need a flush while SSP configured in I2S is BUSY and FMSYNC are * generated, you have to write another function * (loop on BUSY bit and do not limit the flush to at most 16 samples) * * Output parameters * int : number of samples flushed */ int intel_mid_i2s_flush(struct intel_mid_i2s_hdl *drv_data) { u32 sssr, data; u32 num = 0; void __iomem *reg; WARN(!drv_data, "Driver data=NULL\n"); if (!drv_data) return 0; reg = drv_data->ioaddr; sssr = read_SSSR(reg); dev_warn(&drv_data->pdev->dev, "in flush sssr=0x%08X\n", sssr); /* * Flush "by hand" was generating spurious DMA SERV REQUEST * from SSP to DMA => then buggy retrieval of data for next dma_req * Disable: RX Service Request from RX fifo to DMA * as we will flush by hand */ clear_SSCR1_reg(reg, RSRE); /* i2s_flush is called in between 2 bursts * => no FMSYNC at that time (i.e. SSP not busy) * => at most 16 samples in the FIFO */ while ((read_SSSR(reg) & (SSSR_RNE_MASK<<SSSR_RNE_SHIFT)) && (num < FIFO_SIZE)) { data = read_SSDR(reg); num++; } /* Enable: RX Service Request from RX fifo to DMA * as flush by hand is done */ set_SSCR1_reg(reg, RSRE); sssr = read_SSSR(reg); dev_dbg(&drv_data->pdev->dev, "out flush sssr=0x%08X\n", sssr); return num; }
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; }
int pxa2xx_spi_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_CS(drv_data, SSSR_ROR); return limit; }
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 ssp1_dump_registers(struct intel_mid_i2s_hdl *drv_data) { u32 irq_status; void __iomem *reg = drv_data->ioaddr; struct device *ddbg = &(drv_data->pdev->dev); u32 status; irq_status = read_SSSR(reg); dev_dbg(ddbg, "dump SSSR=0x%08X\n", irq_status); status = read_SSCR0(reg); dev_dbg(ddbg, "dump SSCR0=0x%08X\n", status); status = read_SSCR1(reg); dev_dbg(ddbg, "dump SSCR1=0x%08X\n", status); status = read_SSPSP(reg); dev_dbg(ddbg, "dump SSPSP=0x%08X\n", status); status = read_SSTSA(reg); dev_dbg(ddbg, "dump SSTSA=0x%08X\n", status); status = read_SSRSA(reg); dev_dbg(ddbg, "dump SSRSA=0x%08X\n", status); status = read_SSTO(reg); dev_dbg(ddbg, "dump SSTO=0x%08X\n", status); status = read_SSITR(reg); dev_dbg(ddbg, "dump SSITR=0x%08X\n", status); status = read_SSTSS(reg); dev_dbg(ddbg, "dump SSTSS=0x%08X\n", status); status = read_SSACD(reg); dev_dbg(ddbg, "dump SSACD=0x%08X\n", status); }
static int wait_ssp_rx_stall(void const __iomem *ioaddr) { unsigned long limit = loops_per_jiffy << 1; while ((read_SSSR(ioaddr) & SSSR_BSY) && --limit) cpu_relax(); return limit; }
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 bool is_tx_fifo_full(struct driver_data *drv_data) { void __iomem *reg = drv_data->ioaddr; /* workaround for debug UART */ if (drv_data->ssp_type == INTEL_SSP && (drv_data->ssp->port_id == 5)) return ((read_SFIFOL(reg) & 0xFFFF) != 0); else if (!is_lpss_ssp(drv_data)) return ((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK); else return ((read_SSITF(reg) & SSITF_TFL_MASK) == SSITF_TFL_MASK); }
static int u32_reader(struct driver_data *drv_data) { void __iomem *reg = drv_data->ioaddr; while ((read_SSSR(reg) & SSSR_RNE) && (drv_data->rx < drv_data->rx_end)) { *(u32 *)(drv_data->rx) = read_SSDR(reg); drv_data->rx += 4; } return drv_data->rx == drv_data->rx_end; }
static int null_reader(struct driver_data *drv_data) { void __iomem *reg = drv_data->ioaddr; u8 n_bytes = drv_data->n_bytes; while ((read_SSSR(reg) & SSSR_RNE) && (drv_data->rx < drv_data->rx_end)) { read_SSDR(reg); drv_data->rx += n_bytes; } return drv_data->rx == drv_data->rx_end; }
static int u32_writer(struct driver_data *drv_data) { void __iomem *reg = drv_data->ioaddr; if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK) || (drv_data->tx == drv_data->tx_end)) return 0; write_SSDR(*(u32 *)(drv_data->tx), reg); drv_data->tx += 4; return 1; }
static int u16_writer(struct driver_data *drv_data) { void __iomem *reg = drv_data->ioaddr; if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) || (drv_data->tx == drv_data->tx_end)) return 0; write_SSDR(*(u16 *)(drv_data->tx), reg); drv_data->tx += 2; return 1; }
static int null_writer(struct driver_data *drv_data) { void __iomem *reg = drv_data->ioaddr; u8 n_bytes = drv_data->n_bytes; if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK) || (drv_data->tx == drv_data->tx_end)) return 0; write_SSDR(0, reg); drv_data->tx += n_bytes; return 1; }
/* * apl_i2s_send - Send audio samples to I2s controller. * @me: I2sOps structure * @data: Audio samples * @length: Number of samples * * Send audio samples to I2s controller. */ static int apl_i2s_send(I2sOps *me, unsigned int *data, unsigned int length) { int i; uint64_t start; AplI2s *bus = container_of(me, AplI2s, ops); struct AplI2sRegs *i2s_reg = bus->regs; if (!bus->initialized) { if (apl_i2s_init(bus)) return -1; bus->initialized = 1; } if (length < LPE_SSP_FIFO_SIZE) { printf("%s : Invalid data size\n", __func__); return -1; } gpio_set(bus->sdmode_gpio, 1); for (i = 0; i < LPE_SSP_FIFO_SIZE; i++) writel(*data++, &i2s_reg->ssdr); i2s_enable(bus->regs); length -= LPE_SSP_FIFO_SIZE; while (length > 0) { start = timer_us(0); if (read_SSSR(bus->regs) & 0x4) { writel(*data++, &i2s_reg->ssdr); length--; } else { if (timer_us(start) > 100000) { i2s_disable(bus->regs); gpio_set(bus->sdmode_gpio, 0); printf("I2S Transfer Timeout\n"); return -1; } } } mdelay(1); gpio_set(bus->sdmode_gpio, 0); i2s_disable(bus->regs); return 0; }
/** * intel_mid_i2s_get_tx_fifo_level - returns I2S tx fifo level * @drv_data : pointer on private i2s driver data (by i2s_open function) * * Output parameters * int : number of samples currently in the TX FIFO (negative = error) */ int intel_mid_i2s_get_tx_fifo_level(struct intel_mid_i2s_hdl *drv_data) { u32 sssr; u32 tnf, tfl; void __iomem *reg; WARN(!drv_data, "Driver data=NULL\n"); if (!drv_data) return -EFAULT; reg = drv_data->ioaddr; sssr = read_SSSR(reg); tfl = GET_SSSR_val(sssr, TFL); tnf = GET_SSSR_val(sssr, TFN); if (!tnf) return 16; else return tfl; }
/** * intel_mid_i2s_get_rx_fifo_level - returns I2S rx fifo level * @drv_data : pointer on private i2s driver data (by i2s_open function) * * Output parameters * int : Number of samples currently in the RX FIFO (negative = error) */ int intel_mid_i2s_get_rx_fifo_level(struct intel_mid_i2s_hdl *drv_data) { u32 sssr; u32 rne, rfl; void __iomem *reg; WARN(!drv_data, "Driver data=NULL\n"); if (!drv_data) return -EFAULT; reg = drv_data->ioaddr; sssr = read_SSSR(reg); rfl = GET_SSSR_val(sssr, RFL); rne = GET_SSSR_val(sssr, RNE); if (!rne) return 0; else return rfl+1; }
/** * 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; }