drivers/spi/spi.c

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

File Facts

System
Linux kernel
Corpus path
drivers/spi/spi.c
Extension
.c
Size
141339 bytes
Lines
5140
Domain
Driver Families
Bucket
drivers/spi
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern 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

static int spi_match_device(struct device *dev, const struct device_driver *drv)
{
	const struct spi_device	*spi = to_spi_device(dev);
	const struct spi_driver	*sdrv = to_spi_driver(drv);
	int ret;

	/* Check override first, and if set, only use the named driver */
	ret = device_match_driver_override(dev, drv);
	if (ret >= 0)
		return ret;

	/* Attempt an OF style match */
	if (of_driver_match_device(dev, drv))
		return 1;

	/* Then try ACPI */
	if (acpi_driver_match_device(dev, drv))
		return 1;

	if (sdrv->id_table)
		return !!spi_match_id(sdrv->id_table, spi->modalias);

	return strcmp(spi->modalias, drv->name) == 0;
}

static int spi_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
	const struct spi_device		*spi = to_spi_device(dev);
	int rc;

	rc = acpi_device_uevent_modalias(dev, env);
	if (rc != -ENODEV)
		return rc;

	return add_uevent_var(env, "MODALIAS=%s%s", SPI_MODULE_PREFIX, spi->modalias);
}

static int spi_probe(struct device *dev)
{
	const struct spi_driver		*sdrv = to_spi_driver(dev->driver);
	struct spi_device		*spi = to_spi_device(dev);
	struct fwnode_handle		*fwnode = dev_fwnode(dev);
	int ret;

	ret = of_clk_set_defaults(dev->of_node, false);
	if (ret)
		return ret;

	if (is_of_node(fwnode))
		spi->irq = of_irq_get(dev->of_node, 0);
	else if (is_acpi_device_node(fwnode) && spi->irq < 0)
		spi->irq = acpi_dev_gpio_irq_get(to_acpi_device_node(fwnode), 0);
	if (spi->irq == -EPROBE_DEFER)
		return dev_err_probe(dev, spi->irq, "Failed to get irq\n");
	if (spi->irq < 0)
		spi->irq = 0;

	ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON |
					PD_FLAG_DETACH_POWER_OFF);
	if (ret)
		return ret;

	if (sdrv->probe)
		ret = sdrv->probe(spi);

	return ret;
}

static void spi_remove(struct device *dev)
{
	const struct spi_driver		*sdrv = to_spi_driver(dev->driver);

	if (sdrv->remove)
		sdrv->remove(to_spi_device(dev));
}

static void spi_shutdown(struct device *dev)
{
	if (dev->driver) {
		const struct spi_driver	*sdrv = to_spi_driver(dev->driver);

		if (sdrv->shutdown)
			sdrv->shutdown(to_spi_device(dev));
	}
}

const struct bus_type spi_bus_type = {
	.name		= "spi",
	.dev_groups	= spi_dev_groups,
	.match		= spi_match_device,

Annotation

Implementation Notes