drivers/gpio/gpio-latch.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-latch.c
Extension
.c
Size
6665 bytes
Lines
222
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_latch_priv {
	struct gpio_chip gc;
	struct gpio_descs *clk_gpios;
	struct gpio_descs *latched_gpios;
	int n_latched_gpios;
	unsigned int setup_duration_ns;
	unsigned int clock_duration_ns;
	unsigned long *shadow;
	/*
	 * Depending on whether any of the underlying GPIOs may sleep we either
	 * use a mutex or a spinlock to protect our shadow map.
	 */
	union {
		struct mutex mutex; /* protects @shadow */
		spinlock_t spinlock; /* protects @shadow */
	};
};

static int gpio_latch_get_direction(struct gpio_chip *gc, unsigned int offset)
{
	return GPIO_LINE_DIRECTION_OUT;
}

static int gpio_latch_set_unlocked(struct gpio_latch_priv *priv,
				   int (*set)(struct gpio_desc *desc, int value),
				   unsigned int offset, bool val)
{
	int latch = offset / priv->n_latched_gpios, i, ret;

	assign_bit(offset, priv->shadow, val);

	for (i = 0; i < priv->n_latched_gpios; i++) {
		ret = set(priv->latched_gpios->desc[i],
			  test_bit(latch * priv->n_latched_gpios + i,
				   priv->shadow));
		if (ret)
			return ret;
	}

	ndelay(priv->setup_duration_ns);
	set(priv->clk_gpios->desc[latch], 1);
	ndelay(priv->clock_duration_ns);
	set(priv->clk_gpios->desc[latch], 0);

	return 0;
}

static int gpio_latch_set(struct gpio_chip *gc, unsigned int offset, int val)
{
	struct gpio_latch_priv *priv = gpiochip_get_data(gc);

	guard(spinlock_irqsave)(&priv->spinlock);

	return gpio_latch_set_unlocked(priv, gpiod_set_value, offset, val);
}

static int gpio_latch_set_can_sleep(struct gpio_chip *gc, unsigned int offset, int val)
{
	struct gpio_latch_priv *priv = gpiochip_get_data(gc);

	guard(mutex)(&priv->mutex);

	return gpio_latch_set_unlocked(priv, gpiod_set_value_cansleep, offset, val);
}

static bool gpio_latch_can_sleep(struct gpio_latch_priv *priv, unsigned int n_latches)
{
	int i;

	for (i = 0; i < n_latches; i++)
		if (gpiod_cansleep(priv->clk_gpios->desc[i]))
			return true;

	for (i = 0; i < priv->n_latched_gpios; i++)
		if (gpiod_cansleep(priv->latched_gpios->desc[i]))
			return true;

	return false;
}

/*
 * Some value which is still acceptable to delay in atomic context.
 * If we need to go higher we might have to switch to usleep_range(),
 * but that cannot ne used in atomic context and the driver would have
 * to be adjusted to support that.
 */
#define DURATION_NS_MAX 5000

static int gpio_latch_probe(struct platform_device *pdev)
{

Annotation

Implementation Notes