drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c

Source file repositories/reference/linux-study-clean/drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c

File Facts

System
Linux kernel
Corpus path
drivers/pinctrl/sunxi/pinctrl-sunxi-dt.c
Extension
.c
Size
10689 bytes
Lines
374
Domain
Driver Families
Bucket
drivers/pinctrl
Inferred role
Driver Families: implementation source
Status
source 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 (pins_per_bank[i] < 10) {
			/* 4 bytes for "PXy\0" */
			name_size += pins_per_bank[i] * 4;
		} else {
			/* 4 bytes for each "PXy\0" */
			name_size += 10 * 4;

			/* 5 bytes for each "PXyy\0" */
			name_size += (pins_per_bank[i] - 10) * 5;
		}
	}

	if (desc->npins == 0) {
		dev_err(dev, "no ports defined\n");
		return ERR_PTR(-EINVAL);
	}

	pins = devm_kcalloc(dev, desc->npins, sizeof(*pins), GFP_KERNEL);
	if (!pins)
		return ERR_PTR(-ENOMEM);

	/* Allocate memory to store the name for every pin. */
	pin_names = devm_kmalloc(dev, name_size, GFP_KERNEL);
	if (!pin_names)
		return ERR_PTR(-ENOMEM);

	/* Fill the pins array with the name and the number for each pin. */
	cur_name = pin_names;
	cur_pin = pins;
	for (i = 0; i < SUNXI_PINCTRL_MAX_BANKS; i++) {
		for (j = 0; j < pins_per_bank[i]; j++, cur_pin++) {
			int nchars = sprintf(cur_name, "P%c%d",
					     port_base + 'A' + i, j);

			cur_pin->pin.number = (port_base + i) * PINS_PER_BANK + j;
			cur_pin->pin.name = cur_name;
			cur_name += nchars + 1;
		}
	}

	return pins;
}

/*
 * Work out the number of functions for each pin. This will visit every
 * child node of the pinctrl DT node to find all advertised functions.
 * Provide memory to hold the per-function information and assign it to
 * the pin table.
 * Fill in the GPIO in/out functions already (that every pin has), also add
 * an "irq" function at the end, for those pins in IRQ-capable ports.
 * We do not fill in the extra functions (those describe in DT nodes) yet.
 * We (ab)use the "variant" member in each pin to keep track of the number of
 * extra functions needed. At the end this will get reset to 2, so that we
 * can add extra function later, after the two GPIO functions.
 */
static int prepare_function_table(struct device *dev, struct device_node *pnode,
				  struct sunxi_desc_pin *pins, int npins,
				  unsigned pin_base, const u8 *irq_bank_muxes)
{
	struct device_node *node;
	struct property *prop;
	struct sunxi_desc_function *func;
	int num_funcs, irq_bank, last_bank, i;

	/*
	 * We need at least three functions per pin:
	 * - one for GPIO in
	 * - one for GPIO out
	 * - one for the sentinel signalling the end of the list
	 */
	num_funcs = 3 * npins;

	/*
	 * Add a function for each pin in a bank supporting interrupts.
	 * We temporarily (ab)use the variant field to store the number of
	 * functions per pin. This will be cleaned back to 0 before we hand
	 * over the whole structure to the generic sunxi pinctrl setup code.
	 */
	for (i = 0; i < npins; i++) {
		struct sunxi_desc_pin *pin = &pins[i];
		int bank = (pin->pin.number - pin_base) / PINS_PER_BANK;

		if (irq_bank_muxes[bank]) {
			pin->variant++;
			num_funcs++;
		}
	}

	/*
	 * Go over each pin group (every child of the pinctrl DT node) and

Annotation

Implementation Notes