Esempio n. 1
0
/**
 * Put message queue into TXB.
 *
 * @tx: TXB bits(Bit 0 -- TXB0, Bit 1 -- TXB1, Bit 2 -- TXB2)
 */
static void transmit_message(uint8_t tx)
{
	struct can_frame frame;
	uint8_t rts = 0;

	/* Clear interrupt flags */
	mcp2515_bit_modify(CANINTF, tx << TXIF_SHF, 0);

	/* Load messages into empty TX buffers. */
	for (int i = TXB_NUM - 1; i >= 0; i--) {
		if (tx & BIT(i)) {
			canid_clear_cache(i);
			switch (i) {
				case 0:
					txb0_ack_emit();
					break;
				case 1:
					txb1_ack_emit();
					break;
				case 2:
					txb2_ack_emit();
					break;
				default:
					break;
			}

			if (tx_queue_pop(&frame)) {
				/* Make sure the previous message is sent. */
				while (mcp2515_read_reg(TXBCTRL(i) & TXBCTRL_TXREQ));
				load_txb(i, &frame);
				rts |= BIT(i);
			} else {
				/* The TX queue is empty, stop transmission. */
				sync_spinlock_lock(&txb_lock);
				xmit_stopped = 1;
				sync_spinlock_unlock(&txb_lock);
			}
		}
	}

	/* Initiating transmission */
	mcp2515_rts(rts);
}
Esempio n. 2
0
/*
 * Note about handling of error return of mcp251x_spi_trans: accessing
 * registers via SPI is not really different conceptually than using
 * normal I/O assembler instructions, although it's much more
 * complicated from a practical POV. So it's not advisable to always
 * check the return value of this function. Imagine that every
 * read{b,l}, write{b,l} and friends would be bracketed in "if ( < 0)
 * error();", it would be a great mess (well there are some situation
 * when exception handling C++ like could be useful after all). So we
 * just check that transfers are OK at the beginning of our
 * conversation with the chip and to avoid doing really nasty things
 * (like injecting bogus packets in the network stack).
 */
static int mcp251x_spi_trans(struct spi_device *spi, int len)
{
	struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
	struct spi_transfer t = {
		.tx_buf = priv->spi_tx_buf,
		.rx_buf = priv->spi_rx_buf,
		.len = len,
		.cs_change = 0,
	};
	struct spi_message m;
	int ret;

	spi_message_init(&m);

	if (mcp251x_enable_dma) {
		t.tx_dma = priv->spi_tx_dma;
		t.rx_dma = priv->spi_rx_dma;
		m.is_dma_mapped = 1;
	}

	spi_message_add_tail(&t, &m);

	ret = spi_sync(spi, &m);
	if (ret)
		dev_err(&spi->dev, "spi transfer failed: ret = %d\n", ret);
	return ret;
}

static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
{
	struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
	u8 val = 0;

	priv->spi_tx_buf[0] = INSTRUCTION_READ;
	priv->spi_tx_buf[1] = reg;

	mcp251x_spi_trans(spi, 3);
	val = priv->spi_rx_buf[2];

	return val;
}

static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
{
	struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);

	priv->spi_tx_buf[0] = INSTRUCTION_WRITE;
	priv->spi_tx_buf[1] = reg;
	priv->spi_tx_buf[2] = val;

	mcp251x_spi_trans(spi, 3);
}

static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
			       u8 mask, uint8_t val)
{
	struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);

	priv->spi_tx_buf[0] = INSTRUCTION_BIT_MODIFY;
	priv->spi_tx_buf[1] = reg;
	priv->spi_tx_buf[2] = mask;
	priv->spi_tx_buf[3] = val;

	mcp251x_spi_trans(spi, 4);
}

static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf,
				int len, int tx_buf_idx)
{
	struct mcp251x_platform_data *pdata = spi->dev.platform_data;
	struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);

	if (pdata->model == CAN_MCP251X_MCP2510) {
		int i;

		for (i = 1; i < TXBDAT_OFF + len; i++)
			mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + i,
					  buf[i]);
	} else {
		memcpy(priv->spi_tx_buf, buf, TXBDAT_OFF + len);
		mcp251x_spi_trans(spi, TXBDAT_OFF + len);
	}
}

static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
			  int tx_buf_idx)
{
	u32 sid, eid, exide, rtr;
	u8 buf[SPI_TRANSFER_BUF_LEN];

	exide = (frame->can_id & CAN_EFF_FLAG) ? 1 : 0; /* Extended ID Enable */
	if (exide)
		sid = (frame->can_id & CAN_EFF_MASK) >> 18;
	else