drivers/mfd/qcom-spmi-pmic.c

Source file repositories/reference/linux-study-clean/drivers/mfd/qcom-spmi-pmic.c

File Facts

System
Linux kernel
Corpus path
drivers/mfd/qcom-spmi-pmic.c
Extension
.c
Size
8522 bytes
Lines
311
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

struct qcom_spmi_dev {
	int num_usids;
	struct qcom_spmi_pmic pmic;
};

static DEFINE_MUTEX(pmic_spmi_revid_lock);

#define N_USIDS(n)		((void *)n)

static const struct of_device_id pmic_spmi_id_table[] = {
	{ .compatible = "qcom,pm660", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm660l", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8004", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8005", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8019", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8028", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8110", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8150", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8150b", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8150c", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8150l", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8226", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8841", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8901", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8909", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8916", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8937", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8941", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8950", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8994", .data = N_USIDS(2) },
	{ .compatible = "qcom,pm8998", .data = N_USIDS(2) },
	{ .compatible = "qcom,pma8084", .data = N_USIDS(2) },
	{ .compatible = "qcom,pmd9635", .data = N_USIDS(2) },
	{ .compatible = "qcom,pmi8950", .data = N_USIDS(2) },
	{ .compatible = "qcom,pmi8962", .data = N_USIDS(2) },
	{ .compatible = "qcom,pmi8994", .data = N_USIDS(2) },
	{ .compatible = "qcom,pmi8998", .data = N_USIDS(2) },
	{ .compatible = "qcom,pmk8002", .data = N_USIDS(2) },
	{ .compatible = "qcom,pmp8074", .data = N_USIDS(2) },
	{ .compatible = "qcom,smb2351", .data = N_USIDS(2) },
	{ .compatible = "qcom,spmi-pmic", .data = N_USIDS(1) },
	{ }
};

/*
 * A PMIC can be represented by multiple SPMI devices, but
 * only the base PMIC device will contain a reference to
 * the revision information.
 *
 * This function takes a pointer to a pmic device and
 * returns a pointer to the base PMIC device.
 *
 * This only supports PMICs with 1 or 2 USIDs.
 */
static struct spmi_device *qcom_pmic_get_base_usid(struct spmi_device *sdev, struct qcom_spmi_dev *ctx)
{
	struct device_node *spmi_bus;
	int function_parent_usid, ret;
	u32 pmic_addr;

	/*
	 * Quick return if the function device is already in the base
	 * USID. This will always be hit for PMICs with only 1 USID.
	 */
	if (sdev->usid % ctx->num_usids == 0) {
		get_device(&sdev->dev);
		return sdev;
	}

	function_parent_usid = sdev->usid;

	/*
	 * Walk through the list of PMICs until we find the sibling USID.
	 * The goal is to find the first USID which is less than the
	 * number of USIDs in the PMIC array, e.g. for a PMIC with 2 USIDs
	 * where the function device is under USID 3, we want to find the
	 * device for USID 2.
	 */
	spmi_bus = of_get_parent(sdev->dev.of_node);
	sdev = ERR_PTR(-ENODATA);
	for_each_child_of_node_scoped(spmi_bus, child) {
		ret = of_property_read_u32_index(child, "reg", 0, &pmic_addr);
		if (ret) {
			sdev = ERR_PTR(ret);
			break;
		}

		if (pmic_addr == function_parent_usid - (ctx->num_usids - 1)) {
			sdev = spmi_find_device_by_of_node(child);
			if (!sdev) {

Annotation

Implementation Notes