drivers/net/wireless/silabs/wfx/bus_spi.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/silabs/wfx/bus_spi.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/silabs/wfx/bus_spi.c
Extension
.c
Size
8377 bytes
Lines
322
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

struct wfx_spi_priv {
	struct spi_device *func;
	struct wfx_dev *core;
	struct gpio_desc *gpio_reset;
	bool need_swab;
};

/* The chip reads 16bits of data at time and place them directly into (little endian) CPU register.
 * So, the chip expects bytes order to be "B1 B0 B3 B2" (while LE is "B0 B1 B2 B3" and BE is
 * "B3 B2 B1 B0")
 *
 * A little endian host with bits_per_word == 16 should do the right job natively. The code below to
 * support big endian host and commonly used SPI 8bits.
 */
static int wfx_spi_copy_from_io(void *priv, unsigned int addr, void *dst, size_t count)
{
	struct wfx_spi_priv *bus = priv;
	u16 regaddr = (addr << 12) | (count / 2) | SET_READ;
	struct spi_message m;
	struct spi_transfer t_addr = {
		.tx_buf = &regaddr,
		.len = sizeof(regaddr),
	};
	struct spi_transfer t_msg = {
		.rx_buf = dst,
		.len = count,
	};
	u16 *dst16 = dst;
	int ret, i;

	WARN(count % 2, "buffer size must be a multiple of 2");

	cpu_to_le16s(&regaddr);
	if (bus->need_swab)
		swab16s(&regaddr);

	spi_message_init(&m);
	spi_message_add_tail(&t_addr, &m);
	spi_message_add_tail(&t_msg, &m);
	ret = spi_sync(bus->func, &m);

	if (bus->need_swab && addr == WFX_REG_CONFIG)
		for (i = 0; i < count / 2; i++)
			swab16s(&dst16[i]);
	return ret;
}

static int wfx_spi_copy_to_io(void *priv, unsigned int addr, const void *src, size_t count)
{
	struct wfx_spi_priv *bus = priv;
	u16 regaddr = (addr << 12) | (count / 2);
	/* FIXME: use a bounce buffer */
	u16 *src16 = (void *)src;
	int ret, i;
	struct spi_message m;
	struct spi_transfer t_addr = {
		.tx_buf = &regaddr,
		.len = sizeof(regaddr),
	};
	struct spi_transfer t_msg = {
		.tx_buf = src,
		.len = count,
	};

	WARN(count % 2, "buffer size must be a multiple of 2");
	WARN(regaddr & SET_READ, "bad addr or size overflow");

	cpu_to_le16s(&regaddr);

	/* Register address and CONFIG content always use 16bit big endian
	 * ("BADC" order)
	 */
	if (bus->need_swab)
		swab16s(&regaddr);
	if (bus->need_swab && addr == WFX_REG_CONFIG)
		for (i = 0; i < count / 2; i++)
			swab16s(&src16[i]);

	spi_message_init(&m);
	spi_message_add_tail(&t_addr, &m);
	spi_message_add_tail(&t_msg, &m);
	ret = spi_sync(bus->func, &m);

	if (bus->need_swab && addr == WFX_REG_CONFIG)
		for (i = 0; i < count / 2; i++)
			swab16s(&src16[i]);
	return ret;
}

static void wfx_spi_lock(void *priv)

Annotation

Implementation Notes