drivers/mfd/axp20x.c

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

File Facts

System
Linux kernel
Corpus path
drivers/mfd/axp20x.c
Extension
.c
Size
52451 bytes
Lines
1480
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

if (cells_no_irq) {
			axp20x->nr_cells = nr_cells_no_irq;
			axp20x->cells = cells_no_irq;
		} else {
			axp20x->nr_cells = ARRAY_SIZE(axp_regulator_only_cells);
			axp20x->cells = axp_regulator_only_cells;
		}
	}

	dev_info(dev, "AXP20x variant %s found\n",
		 axp20x_model_names[axp20x->variant]);

	return 0;
}
EXPORT_SYMBOL(axp20x_match_device);

int axp20x_device_probe(struct axp20x_dev *axp20x)
{
	int ret;

	/*
	 * The AXP806 supports either master/standalone or slave mode.
	 * Slave mode allows sharing the serial bus, even with multiple
	 * AXP806 which all have the same hardware address.
	 *
	 * This is done with extra "serial interface address extension",
	 * or AXP806_BUS_ADDR_EXT, and "register address extension", or
	 * AXP806_REG_ADDR_EXT, registers. The former is read-only, with
	 * 1 bit customizable at the factory, and 1 bit depending on the
	 * state of an external pin. The latter is writable. The device
	 * will only respond to operations to its other registers when
	 * the these device addressing bits (in the upper 4 bits of the
	 * registers) match.
	 *
	 * By default we support an AXP806 chained to an AXP809 in slave
	 * mode. Boards which use an AXP806 in master mode can set the
	 * property "x-powers,master-mode" to override the default.
	 */
	if (axp20x->variant == AXP806_ID) {
		if (of_property_read_bool(axp20x->dev->of_node,
					  "x-powers,master-mode") ||
		    of_property_read_bool(axp20x->dev->of_node,
					  "x-powers,self-working-mode"))
			regmap_write(axp20x->regmap, AXP806_REG_ADDR_EXT,
				     AXP806_REG_ADDR_EXT_ADDR_MASTER_MODE);
		else
			regmap_write(axp20x->regmap, AXP806_REG_ADDR_EXT,
				     AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE);
	}

	/* Only if there is an interrupt line connected towards the CPU. */
	if (axp20x->irq > 0) {
		ret = regmap_add_irq_chip(axp20x->regmap, axp20x->irq,
				IRQF_ONESHOT | IRQF_SHARED | axp20x->irq_flags,
				-1, axp20x->regmap_irq_chip,
				&axp20x->regmap_irqc);
		if (ret) {
			dev_err(axp20x->dev, "failed to add irq chip: %d\n",
				ret);
			return ret;
		}
	}

	ret = mfd_add_devices(axp20x->dev, PLATFORM_DEVID_NONE, axp20x->cells,
			      axp20x->nr_cells, NULL, 0, NULL);

	if (ret) {
		dev_err(axp20x->dev, "failed to add MFD devices: %d\n", ret);
		regmap_del_irq_chip(axp20x->irq, axp20x->regmap_irqc);
		return ret;
	}

	if (axp20x->variant != AXP288_ID)
		devm_register_power_off_handler(axp20x->dev, axp20x_power_off, axp20x);

	dev_info(axp20x->dev, "AXP20X driver loaded\n");

	return 0;
}
EXPORT_SYMBOL(axp20x_device_probe);

void axp20x_device_remove(struct axp20x_dev *axp20x)
{
	mfd_remove_devices(axp20x->dev);
	regmap_del_irq_chip(axp20x->irq, axp20x->regmap_irqc);
}
EXPORT_SYMBOL(axp20x_device_remove);

MODULE_DESCRIPTION("PMIC MFD core driver for AXP20X");
MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");

Annotation

Implementation Notes