Ejemplo n.º 1
0
/**
 * hsi_unpoll - HSI poll feature, disables data interrupt on frame reception
 * @dev - hsi device channel reference to apply the I/O control
 *						(or port associated to it)
 *
 * Return 0 on success, a negative value on failure.
 *
 */
int hsi_unpoll(struct hsi_device *dev)
{
	struct hsi_channel *ch;
	struct hsi_dev *hsi_ctrl;

	if (unlikely(!dev || !dev->ch))
		return -EINVAL;
	dev_dbg(dev->device.parent, "%s ch %d\n", __func__, dev->n_ch);

	if (unlikely(!(dev->ch->flags & HSI_CH_OPEN))) {
		dev_err(dev->device.parent, "HSI device NOT open\n");
		return -EINVAL;
	}

	ch = dev->ch;
	hsi_ctrl = ch->hsi_port->hsi_controller;

	spin_lock_bh(&hsi_ctrl->lock);
	hsi_clocks_enable_channel(hsi_ctrl->dev, dev->ch->channel_number,
					__func__);

	ch->flags &= ~HSI_CH_RX_POLL;

	hsi_driver_disable_read_interrupt(ch);

	hsi_clocks_disable_channel(hsi_ctrl->dev, dev->ch->channel_number,
				   __func__);
	spin_unlock_bh(&hsi_ctrl->lock);

	return 0;
}
Ejemplo n.º 2
0
/**
 * hsi_close - close given hsi device channel
 * @dev - reference to hsi device channel.
 */
void hsi_close(struct hsi_device *dev)
{
	struct hsi_dev *hsi_ctrl;

	if (!dev || !dev->ch) {
		pr_err(LOG_NAME "Trying to close wrong HSI device %p\n", dev);
		return;
	}
	dev_dbg(dev->device.parent, "%s ch %d\n", __func__, dev->n_ch);

	hsi_ctrl = dev->ch->hsi_port->hsi_controller;

	spin_lock_bh(&hsi_ctrl->lock);

	hsi_clocks_enable_channel(hsi_ctrl->dev, dev->ch->channel_number,
					__func__);

	if (dev->ch->flags & HSI_CH_OPEN) {
		dev->ch->flags &= ~HSI_CH_OPEN;
		__hsi_write_cancel(dev->ch);
		__hsi_read_cancel(dev->ch);
	}

	if (dev->ch->flags & HSI_CH_RX_POLL) {
		/* Disable RX interrupt for polling */
		dev->ch->flags &= ~HSI_CH_RX_POLL;
		hsi_driver_disable_read_interrupt(dev->ch);
	}

	hsi_clocks_disable_channel(hsi_ctrl->dev, dev->ch->channel_number,
				   __func__);
	spin_unlock_bh(&hsi_ctrl->lock);
}
/* HSR_AVAILABLE interrupt processing */
static void hsi_do_channel_rx(struct hsi_channel *ch)
{
	struct hsi_dev *hsi_ctrl = ch->hsi_port->hsi_controller;
	void __iomem *base = ch->hsi_port->hsi_controller->base;
	unsigned int n_ch;
	unsigned int n_p;
	unsigned int irq;
	long buff_offset;
	int rx_poll = 0;
	int data_read = 0;
	int fifo, fifo_words_avail;

	n_ch = ch->channel_number;
	n_p = ch->hsi_port->port_number;
	irq = ch->hsi_port->n_irq;

	dev_dbg(hsi_ctrl->dev,
		"Data Available interrupt for channel %d.\n", n_ch);

	/* Check if there is data in FIFO available for reading */
	if (hsi_driver_device_is_hsi(to_platform_device(hsi_ctrl->dev))) {
		fifo = hsi_fifo_get_id(hsi_ctrl, n_ch, n_p);
		if (unlikely(fifo < 0)) {
			dev_err(hsi_ctrl->dev, "No valid FIFO id found for "
					       "channel %d.\n", n_ch);
			return;
		}
		fifo_words_avail = hsi_get_rx_fifo_occupancy(hsi_ctrl, fifo);
		if (!fifo_words_avail) {
			dev_dbg(hsi_ctrl->dev,
				"WARNING: RX FIFO %d empty before CPU copy\n",
				fifo);

			/* Do not disable interrupt becaue another interrupt */
			/* can still come, this time with a real frame. */
			return;
		}
	}

	/* Disable interrupts if not needed for polling */
	if (!(ch->flags & HSI_CH_RX_POLL))
		hsi_driver_disable_read_interrupt(ch);

	/*
	 * Check race condition: RX transmission initiated but DMA transmission
	 * already started - acknowledge then ignore interrupt occurence
	 */
	if (ch->read_data.lch != -1) {
		dev_warn(hsi_ctrl->dev,
			"Race condition between RX Int ch %d and DMA %0x\n",
			n_ch, ch->read_data.lch);
		goto done;
	}

	if (ch->flags & HSI_CH_RX_POLL)
		rx_poll = 1;

	if (ch->read_data.addr) {
		buff_offset = hsi_hsr_buffer_reg(hsi_ctrl, n_p, n_ch);
		if (buff_offset >= 0) {
			data_read = 1;
			*(ch->read_data.addr) = hsi_inl(base, buff_offset);
		}
	}

	hsi_reset_ch_read(ch);

done:
	if (rx_poll) {
		spin_unlock(&hsi_ctrl->lock);
		hsi_port_event_handler(ch->hsi_port,
				       HSI_EVENT_HSR_DATAAVAILABLE,
				       (void *)n_ch);
		spin_lock(&hsi_ctrl->lock);
	}

	if (data_read) {
		spin_unlock(&hsi_ctrl->lock);
		dev_dbg(hsi_ctrl->dev, "Calling ch %d read callback.\n", n_ch);
		(*ch->read_done) (ch->dev, 1);
		spin_lock(&hsi_ctrl->lock);
	}
}
Ejemplo n.º 4
0
/**
 * hsi_driver_read_dma - Program GDD [DMA] to write data to memory from
 * the hsi channel buffer.
 * @hsi_channel - pointer to the hsi_channel to read data from.
 * @data - 32-bit word pointer where to store the incoming data.
 * @size - Number of 32bit words to be transfered to the buffer.
 *
 * hsi_controller lock must be held before calling this function.
 *
 * Return 0 on success and < 0 on error.
 */
int hsi_driver_read_dma(struct hsi_channel *hsi_channel, u32 * data,
			unsigned int count)
{
	struct hsi_dev *hsi_ctrl = hsi_channel->hsi_port->hsi_controller;
	void __iomem *base = hsi_ctrl->base;
	unsigned int port = hsi_channel->hsi_port->port_number;
	unsigned int channel = hsi_channel->channel_number;
	unsigned int sync;
	int lch;
	dma_addr_t src_addr;
	dma_addr_t dest_addr;
	u16 tmp;
	int fifo;

	lch = hsi_get_free_lch(hsi_ctrl);
	if (lch < 0) {
		dev_err(hsi_ctrl->dev, "No free DMA channels.\n");
		return -EBUSY;	/* No free GDD logical channels. */
	} else {
		dev_dbg(hsi_ctrl->dev, "Allocated DMA channel %d for read on"
					" HSI channel %d.\n", lch,
					hsi_channel->channel_number);
	}

	/* When DMA is used for Rx, disable the Rx Interrupt.
	 * (else DATAAVAILLABLE event would get triggered on first
	 * received data word)
	 * (Rx interrupt might be active for polling feature)
	 */
	hsi_driver_disable_read_interrupt(hsi_channel);

	/*
	 * NOTE: Gettting a free gdd logical channel and
	 * reserve it must be done atomicaly.
	 */
	hsi_channel->read_data.lch = lch;

	/* Sync is required for SSI but not for HSI */
	sync = hsi_sync_table[HSI_SYNC_READ][port - 1][channel];

	dest_addr = dma_map_single(hsi_ctrl->dev, data, count * 4,
				  DMA_FROM_DEVICE);
	if (unlikely(dma_mapping_error(hsi_ctrl->dev, dest_addr))) {
		dev_err(hsi_ctrl->dev, "Failed to create DMA read mapping.\n");
		return -ENOMEM;
	}

	tmp = HSI_DST_BURST_4x32_BIT |
	    HSI_DST_MEMORY_PORT |
	    HSI_SRC_BURST_4x32_BIT |
	    HSI_SRC_PERIPHERAL_PORT | HSI_DATA_TYPE_S32;
	hsi_outw(tmp, base, HSI_GDD_CSDP_REG(lch));

	tmp = HSI_DST_AMODE_POSTINC | HSI_SRC_AMODE_CONST | sync;
	hsi_outw(tmp, base, HSI_GDD_CCR_REG(lch));

	hsi_outw((HSI_BLOCK_IE | HSI_TOUT_IE), base, HSI_GDD_CCIR_REG(lch));

	if (hsi_driver_device_is_hsi(to_platform_device(hsi_ctrl->dev))) {
		fifo = hsi_fifo_get_id(hsi_ctrl, channel, port);
		if (unlikely(fifo < 0)) {
			dev_err(hsi_ctrl->dev, "No valid FIFO id for DMA "
				"transfer from FIFO.\n");
			return -EFAULT;
		}
		/* HSI CSSA register takes a FIFO ID when copying from FIFO */
		hsi_outl(fifo, base, HSI_GDD_CSSA_REG(lch));
	} else{
		src_addr = hsi_ctrl->phy_base + HSI_HSR_BUFFER_CH_REG(port,
								channel);
		/* SSI CSSA register always takes a 32-bit address */
		hsi_outl(src_addr, base, HSI_GDD_CSSA_REG(lch));
	}

	/* HSI CDSA register takes a 32-bit address when copying to memory */
	/* SSI CDSA register always takes a 32-bit address */
	hsi_outl(dest_addr, base, HSI_GDD_CDSA_REG(lch));
	hsi_outw(count, base, HSI_GDD_CEN_REG(lch));

	/* TODO : Need to clean interrupt status here to avoid spurious int */

	hsi_outl_or(HSI_GDD_LCH(lch), base, HSI_SYS_GDD_MPU_IRQ_ENABLE_REG);
	hsi_outw_or(HSI_CCR_ENABLE, base, HSI_GDD_CCR_REG(lch));

	return 0;
}