drivers/amba/bus.c

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

File Facts

System
Linux kernel
Corpus path
drivers/amba/bus.c
Extension
.c
Size
16658 bytes
Lines
682
Domain
Driver Families
Bucket
drivers/amba
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 amba_match(struct device *dev, const struct device_driver *drv)
{
	struct amba_device *pcdev = to_amba_device(dev);
	const struct amba_driver *pcdrv = to_amba_driver(drv);
	int ret;

	mutex_lock(&pcdev->periphid_lock);
	if (!pcdev->periphid) {
		ret = amba_read_periphid(pcdev);

		/*
		 * Returning any error other than -EPROBE_DEFER from bus match
		 * can cause driver registration failure. So, if there's a
		 * permanent failure in reading pid and cid, simply map it to
		 * -EPROBE_DEFER.
		 */
		if (ret) {
			mutex_unlock(&pcdev->periphid_lock);
			return -EPROBE_DEFER;
		}
		dev_set_uevent_suppress(dev, false);
		kobject_uevent(&dev->kobj, KOBJ_ADD);
	}
	mutex_unlock(&pcdev->periphid_lock);

	/* When driver_override is set, only bind to the matching driver */
	ret = device_match_driver_override(dev, drv);
	if (ret >= 0)
		return ret;

	return amba_lookup(pcdrv->id_table, pcdev) != NULL;
}

static int amba_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
	const struct amba_device *pcdev = to_amba_device(dev);
	int retval = 0;

	retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid);
	if (retval)
		return retval;

	retval = add_uevent_var(env, "MODALIAS=amba:d%08X", pcdev->periphid);
	return retval;
}

static int of_amba_device_decode_irq(struct amba_device *dev)
{
	struct device_node *node = dev->dev.of_node;
	int i, irq = 0;

	if (IS_ENABLED(CONFIG_OF_IRQ) && node) {
		/* Decode the IRQs and address ranges */
		for (i = 0; i < AMBA_NR_IRQS; i++) {
			irq = of_irq_get(node, i);
			if (irq < 0) {
				if (irq == -EPROBE_DEFER)
					return irq;
				irq = 0;
			}

			dev->irq[i] = irq;
		}
	}

	return 0;
}

/*
 * These are the device model conversion veneers; they convert the
 * device model structures to our more specific structures.
 */
static int amba_probe(struct device *dev)
{
	struct amba_device *pcdev = to_amba_device(dev);
	struct amba_driver *pcdrv = to_amba_driver(dev->driver);
	const struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev);
	int ret;

	do {
		ret = of_amba_device_decode_irq(pcdev);
		if (ret)
			break;

		ret = of_clk_set_defaults(dev->of_node, false);
		if (ret < 0)
			break;

		ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON |
						PD_FLAG_DETACH_POWER_OFF);

Annotation

Implementation Notes