drivers/net/can/spi/mcp251xfd/mcp251xfd-regmap.c

Source file repositories/reference/linux-study-clean/drivers/net/can/spi/mcp251xfd/mcp251xfd-regmap.c

File Facts

System
Linux kernel
Corpus path
drivers/net/can/spi/mcp251xfd/mcp251xfd-regmap.c
Extension
.c
Size
19157 bytes
Lines
688
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

mcp251xfd_for_each_rx_ring(priv, ring, n) {
			if (reg == MCP251XFD_REG_FIFOCON(ring->fifo_nr))
				return false;
			if (reg == MCP251XFD_REG_FIFOSTA(ring->fifo_nr))
				return true;
		}

		WARN(1, "Status of reg 0x%04x unknown.\n", reg);
	}

	return true;
}

static int
mcp251xfd_regmap_nocrc_update_bits(void *context, unsigned int reg,
				   unsigned int mask, unsigned int val)
{
	struct spi_device *spi = context;
	struct mcp251xfd_priv *priv = spi_get_drvdata(spi);
	struct mcp251xfd_map_buf_nocrc *buf_rx = priv->map_buf_nocrc_rx;
	struct mcp251xfd_map_buf_nocrc *buf_tx = priv->map_buf_nocrc_tx;
	__le32 orig_le32 = 0, mask_le32, val_le32, tmp_le32;
	u8 first_byte, last_byte, len;
	int err;

	BUILD_BUG_ON(sizeof(buf_rx->cmd) != sizeof(__be16));
	BUILD_BUG_ON(sizeof(buf_tx->cmd) != sizeof(__be16));

	if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) &&
	    mask == 0)
		return -EINVAL;

	first_byte = mcp251xfd_first_byte_set(mask);
	last_byte = mcp251xfd_last_byte_set(mask);
	len = last_byte - first_byte + 1;

	if (mcp251xfd_update_bits_read_reg(priv, reg)) {
		struct spi_transfer xfer[2] = { };
		struct spi_message msg;

		spi_message_init(&msg);
		spi_message_add_tail(&xfer[0], &msg);

		if (priv->devtype_data.quirks & MCP251XFD_QUIRK_HALF_DUPLEX) {
			xfer[0].tx_buf = buf_tx;
			xfer[0].len = sizeof(buf_tx->cmd);

			xfer[1].rx_buf = buf_rx->data;
			xfer[1].len = len;
			spi_message_add_tail(&xfer[1], &msg);
		} else {
			xfer[0].tx_buf = buf_tx;
			xfer[0].rx_buf = buf_rx;
			xfer[0].len = sizeof(buf_tx->cmd) + len;

			if (MCP251XFD_SANITIZE_SPI)
				memset(buf_tx->data, 0x0, len);
		}

		mcp251xfd_spi_cmd_read_nocrc(&buf_tx->cmd, reg + first_byte);
		err = spi_sync(spi, &msg);
		if (err)
			return err;

		memcpy(&orig_le32, buf_rx->data, len);
	}

	mask_le32 = cpu_to_le32(mask >> BITS_PER_BYTE * first_byte);
	val_le32 = cpu_to_le32(val >> BITS_PER_BYTE * first_byte);

	tmp_le32 = orig_le32 & ~mask_le32;
	tmp_le32 |= val_le32 & mask_le32;

	reg += first_byte;
	mcp251xfd_spi_cmd_write_nocrc(&buf_tx->cmd, reg);
	return mcp251xfd_regmap_nocrc_gather_write(context, &buf_tx->cmd, 2, &tmp_le32, len);
}

static int
mcp251xfd_regmap_nocrc_read(void *context,
			    const void *reg, size_t reg_len,
			    void *val_buf, size_t val_len)
{
	struct spi_device *spi = context;
	struct mcp251xfd_priv *priv = spi_get_drvdata(spi);
	struct mcp251xfd_map_buf_nocrc *buf_rx = priv->map_buf_nocrc_rx;
	struct mcp251xfd_map_buf_nocrc *buf_tx = priv->map_buf_nocrc_tx;
	struct spi_transfer xfer[2] = { };
	struct spi_message msg;
	int err;

Annotation

Implementation Notes