drivers/spi/spi-xcomm.c

Source file repositories/reference/linux-study-clean/drivers/spi/spi-xcomm.c

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi-xcomm.c
Extension
.c
Size
6837 bytes
Lines
289
Domain
Driver Families
Bucket
drivers/spi
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 spi_xcomm {
	struct i2c_client *i2c;

	struct gpio_chip gc;

	u16 settings;
	u16 chipselect;

	unsigned int current_speed;

	u8 buf[63];
};

static int spi_xcomm_gpio_set_value(struct gpio_chip *chip,
				    unsigned int offset, int val)
{
	struct spi_xcomm *spi_xcomm = gpiochip_get_data(chip);
	unsigned char buf[2];

	buf[0] = SPI_XCOMM_CMD_GPIO_SET;
	buf[1] = !!val;

	return i2c_master_send(spi_xcomm->i2c, buf, 2);
}

static int spi_xcomm_gpio_get_direction(struct gpio_chip *chip,
					unsigned int offset)
{
	return GPIO_LINE_DIRECTION_OUT;
}

static int spi_xcomm_gpio_add(struct spi_xcomm *spi_xcomm)
{
	struct device *dev = &spi_xcomm->i2c->dev;

	if (!IS_ENABLED(CONFIG_GPIOLIB))
		return 0;

	spi_xcomm->gc.get_direction = spi_xcomm_gpio_get_direction;
	spi_xcomm->gc.set = spi_xcomm_gpio_set_value;
	spi_xcomm->gc.can_sleep = 1;
	spi_xcomm->gc.base = -1;
	spi_xcomm->gc.ngpio = 1;
	spi_xcomm->gc.label = spi_xcomm->i2c->name;
	spi_xcomm->gc.owner = THIS_MODULE;

	return devm_gpiochip_add_data(dev, &spi_xcomm->gc, spi_xcomm);
}

static int spi_xcomm_sync_config(struct spi_xcomm *spi_xcomm, unsigned int len)
{
	u16 settings;
	u8 *buf = spi_xcomm->buf;

	settings = spi_xcomm->settings;
	settings |= len << SPI_XCOMM_SETTINGS_LEN_OFFSET;

	buf[0] = SPI_XCOMM_CMD_UPDATE_CONFIG;
	put_unaligned_be16(settings, &buf[1]);
	put_unaligned_be16(spi_xcomm->chipselect, &buf[3]);

	return i2c_master_send(spi_xcomm->i2c, buf, 5);
}

static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm,
				 struct spi_device *spi, int is_active)
{
	unsigned long cs = spi_get_chipselect(spi, 0);
	u16 chipselect = spi_xcomm->chipselect;

	if (is_active)
		chipselect |= BIT(cs);
	else
		chipselect &= ~BIT(cs);

	spi_xcomm->chipselect = chipselect;
}

static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
				    struct spi_device *spi, struct spi_transfer *t,
				    unsigned int *settings)
{
	if (t->len > 62)
		return -EINVAL;

	if (t->speed_hz != spi_xcomm->current_speed) {
		unsigned int divider;

		divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, t->speed_hz);
		if (divider >= 64)

Annotation

Implementation Notes