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);
}
Пример #3
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);
}
Пример #4
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;
}
Пример #5
0
/*
 * 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);
}
Пример #6
0
/**
 * 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;
}
Пример #7
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;
}