drivers/net/can/m_can/tcan4x5x-regmap.c

Source file repositories/reference/linux-study-clean/drivers/net/can/m_can/tcan4x5x-regmap.c

File Facts

System
Linux kernel
Corpus path
drivers/net/can/m_can/tcan4x5x-regmap.c
Extension
.c
Size
4899 bytes
Lines
166
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

// SPDX-License-Identifier: GPL-2.0
//
// tcan4x5x - Texas Instruments TCAN4x5x Family CAN controller driver
//
// Copyright (c) 2020 Pengutronix,
//                    Marc Kleine-Budde <kernel@pengutronix.de>
// Copyright (c) 2018-2019 Texas Instruments Incorporated
//                    http://www.ti.com/

#include "tcan4x5x.h"

#define TCAN4X5X_SPI_INSTRUCTION_WRITE (0x61 << 24)
#define TCAN4X5X_SPI_INSTRUCTION_READ (0x41 << 24)

#define TCAN4X5X_MAX_REGISTER 0x87fc

static int tcan4x5x_regmap_gather_write(void *context,
					const void *reg, size_t reg_len,
					const void *val, size_t val_len)
{
	struct spi_device *spi = context;
	struct tcan4x5x_priv *priv = spi_get_drvdata(spi);
	struct tcan4x5x_map_buf *buf_tx = &priv->map_buf_tx;
	struct spi_transfer xfer[] = {
		{
			.tx_buf = buf_tx,
			.len = sizeof(buf_tx->cmd) + val_len,
		},
	};

	memcpy(&buf_tx->cmd, reg, sizeof(buf_tx->cmd.cmd) +
	       sizeof(buf_tx->cmd.addr));
	tcan4x5x_spi_cmd_set_len(&buf_tx->cmd, val_len);
	memcpy(buf_tx->data, val, val_len);

	return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));
}

static int tcan4x5x_regmap_write(void *context, const void *data, size_t count)
{
	return tcan4x5x_regmap_gather_write(context, data, sizeof(__be32),
					    data + sizeof(__be32),
					    count - sizeof(__be32));
}

static int tcan4x5x_regmap_read(void *context,
				const void *reg_buf, size_t reg_len,
				void *val_buf, size_t val_len)
{
	struct spi_device *spi = context;
	struct tcan4x5x_priv *priv = spi_get_drvdata(spi);
	struct tcan4x5x_map_buf *buf_rx = &priv->map_buf_rx;
	struct tcan4x5x_map_buf *buf_tx = &priv->map_buf_tx;
	struct spi_transfer xfer[2] = {
		{
			.tx_buf = buf_tx,
		}
	};
	struct spi_message msg;
	int err;

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

	memcpy(&buf_tx->cmd, reg_buf, sizeof(buf_tx->cmd.cmd) +
	       sizeof(buf_tx->cmd.addr));
	tcan4x5x_spi_cmd_set_len(&buf_tx->cmd, val_len);

	if (spi->controller->flags & SPI_CONTROLLER_HALF_DUPLEX) {
		xfer[0].len = sizeof(buf_tx->cmd);

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

		if (TCAN4X5X_SANITIZE_SPI)
			memset(buf_tx->data, 0x0, val_len);
	}

	err = spi_sync(spi, &msg);
	if (err)
		return err;

	if (!(spi->controller->flags & SPI_CONTROLLER_HALF_DUPLEX))
		memcpy(val_buf, buf_rx->data, val_len);

	return 0;

Annotation

Implementation Notes