drivers/gpio/gpio-shared-proxy.c

Source file repositories/reference/linux-study-clean/drivers/gpio/gpio-shared-proxy.c

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-shared-proxy.c
Extension
.c
Size
8930 bytes
Lines
344
Domain
Driver Families
Bucket
drivers/gpio
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

struct gpio_shared_proxy_data {
	struct gpio_chip gc;
	struct gpio_shared_desc *shared_desc;
	struct device *dev;
	bool voted_high;
};

static int
gpio_shared_proxy_set_unlocked(struct gpio_shared_proxy_data *proxy,
			       int (*set_func)(struct gpio_desc *desc, int value),
			       int value)
{
	struct gpio_shared_desc *shared_desc = proxy->shared_desc;
	struct gpio_desc *desc = shared_desc->desc;
	int ret = 0;

	gpio_shared_lockdep_assert(shared_desc);

	if (value) {
	       /* User wants to set value to high. */
		if (proxy->voted_high)
			/* Already voted for high, nothing to do. */
			goto out;

		/* Haven't voted for high yet. */
		if (!shared_desc->highcnt) {
			/*
			 * Current value is low, need to actually set value
			 * to high.
			 */
			ret = set_func(desc, 1);
			if (ret)
				goto out;
		}

		shared_desc->highcnt++;
		proxy->voted_high = true;

		goto out;
	}

	/* Desired value is low. */
	if (!proxy->voted_high)
		/* We didn't vote for high, nothing to do. */
		goto out;

	/* We previously voted for high. */
	if (shared_desc->highcnt == 1) {
		/* This is the last remaining vote for high, set value  to low. */
		ret = set_func(desc, 0);
		if (ret)
			goto out;
	}

	shared_desc->highcnt--;
	proxy->voted_high = false;

out:
	if (shared_desc->highcnt)
		dev_dbg(proxy->dev,
			"Voted for value '%s', effective value is 'high', number of votes for 'high': %u\n",
			str_high_low(value), shared_desc->highcnt);
	else
		dev_dbg(proxy->dev, "Voted for value 'low', effective value is 'low'\n");

	return ret;
}

static int gpio_shared_proxy_request(struct gpio_chip *gc, unsigned int offset)
{
	struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc);
	struct gpio_shared_desc *shared_desc = proxy->shared_desc;

	guard(gpio_shared_desc_lock)(shared_desc);

	proxy->shared_desc->usecnt++;

	dev_dbg(proxy->dev, "Shared GPIO requested, number of users: %u\n",
		proxy->shared_desc->usecnt);

	return 0;
}

static void gpio_shared_proxy_free(struct gpio_chip *gc, unsigned int offset)
{
	struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc);
	struct gpio_shared_desc *shared_desc = proxy->shared_desc;
	int ret;

	guard(gpio_shared_desc_lock)(shared_desc);

Annotation

Implementation Notes