Пример #1
0
/**
 * 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;
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #5
0
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;
}
Пример #7
0
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);
}
Пример #9
0
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;
}
Пример #10
0
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;
}
Пример #11
0
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;
}
Пример #12
0
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;
}
Пример #13
0
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;
}
Пример #14
0
/*
 * 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;
}
Пример #15
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;
}
Пример #16
0
/**
 * 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;
}
Пример #17
0
/**
 * 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;
}