drivers/mfd/ucb1x00-core.c

Source file repositories/reference/linux-study-clean/drivers/mfd/ucb1x00-core.c

File Facts

System
Linux kernel
Corpus path
drivers/mfd/ucb1x00-core.c
Extension
.c
Size
19889 bytes
Lines
782
Domain
Driver Families
Bucket
drivers/mfd
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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

ret = device_add(&ucb->dev);
	if (ret)
		goto err_dev_add;

	ucb1x00_enable(ucb);
	ucb->irq = ucb1x00_detect_irq(ucb);
	ucb1x00_disable(ucb);
	if (!ucb->irq) {
		dev_err(&ucb->dev, "IRQ probe failed\n");
		ret = -ENODEV;
		goto err_no_irq;
	}

	ucb->gpio.base = -1;
	irq_base = pdata ? pdata->irq_base : 0;
	ucb->irq_base = irq_alloc_descs(-1, irq_base, 16, -1);
	if (ucb->irq_base < 0) {
		dev_err(&ucb->dev, "unable to allocate 16 irqs: %d\n",
			ucb->irq_base);
		ret = ucb->irq_base;
		goto err_irq_alloc;
	}

	for (i = 0; i < 16; i++) {
		unsigned irq = ucb->irq_base + i;

		irq_set_chip_and_handler(irq, &ucb1x00_irqchip, handle_edge_irq);
		irq_set_chip_data(irq, ucb);
		irq_clear_status_flags(irq, IRQ_NOREQUEST);
	}

	irq_set_irq_type(ucb->irq, IRQ_TYPE_EDGE_RISING);
	irq_set_chained_handler_and_data(ucb->irq, ucb1x00_irq, ucb);

	if (pdata && pdata->gpio_base) {
		ucb->gpio.label = dev_name(&ucb->dev);
		ucb->gpio.parent = &ucb->dev;
		ucb->gpio.owner = THIS_MODULE;
		ucb->gpio.base = pdata->gpio_base;
		ucb->gpio.ngpio = 10;
		ucb->gpio.set = ucb1x00_gpio_set;
		ucb->gpio.get = ucb1x00_gpio_get;
		ucb->gpio.direction_input = ucb1x00_gpio_direction_input;
		ucb->gpio.direction_output = ucb1x00_gpio_direction_output;
		ucb->gpio.to_irq = ucb1x00_to_irq;
		ret = gpiochip_add_data(&ucb->gpio, ucb);
		if (ret)
			goto err_gpio_add;
	} else
		dev_info(&ucb->dev, "gpio_base not set so no gpiolib support");

	mcp_set_drvdata(mcp, ucb);

	if (pdata)
		device_set_wakeup_capable(&ucb->dev, pdata->can_wakeup);

	INIT_LIST_HEAD(&ucb->devs);
	mutex_lock(&ucb1x00_mutex);
	list_add_tail(&ucb->node, &ucb1x00_devices);
	list_for_each_entry(drv, &ucb1x00_drivers, node) {
		ucb1x00_add_dev(ucb, drv);
	}
	mutex_unlock(&ucb1x00_mutex);

	return ret;

 err_gpio_add:
	irq_set_chained_handler(ucb->irq, NULL);
 err_irq_alloc:
	if (ucb->irq_base > 0)
		irq_free_descs(ucb->irq_base, 16);
 err_no_irq:
	device_del(&ucb->dev);
 err_dev_add:
	put_device(&ucb->dev);
 out:
	if (pdata && pdata->reset)
		pdata->reset(UCB_RST_PROBE_FAIL);
	return ret;
}

static void ucb1x00_remove(struct mcp *mcp)
{
	struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data;
	struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
	struct list_head *l, *n;

	mutex_lock(&ucb1x00_mutex);
	list_del(&ucb->node);
	list_for_each_safe(l, n, &ucb->devs) {

Annotation

Implementation Notes