drivers/gpio/gpio-raspberrypi-exp.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-raspberrypi-exp.c
Extension
.c
Size
6424 bytes
Lines
260
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 rpi_exp_gpio {
	struct gpio_chip gc;
	struct rpi_firmware *fw;
};

/* VC4 firmware mailbox interface data structures */

struct gpio_set_config {
	u32 gpio;
	u32 direction;
	u32 polarity;
	u32 term_en;
	u32 term_pull_up;
	u32 state;
};

struct gpio_get_config {
	u32 gpio;
	u32 direction;
	u32 polarity;
	u32 term_en;
	u32 term_pull_up;
};

struct gpio_get_set_state {
	u32 gpio;
	u32 state;
};

static int rpi_exp_gpio_get_polarity(struct gpio_chip *gc, unsigned int off)
{
	struct rpi_exp_gpio *gpio;
	struct gpio_get_config get;
	int ret;

	gpio = gpiochip_get_data(gc);

	get.gpio = off + RPI_EXP_GPIO_BASE;	/* GPIO to update */

	ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_CONFIG,
				    &get, sizeof(get));
	if (ret || get.gpio != 0) {
		dev_err(gc->parent, "Failed to get GPIO %u config (%d %x)\n",
			off, ret, get.gpio);
		return ret ? ret : -EIO;
	}
	return get.polarity;
}

static int rpi_exp_gpio_dir_in(struct gpio_chip *gc, unsigned int off)
{
	struct rpi_exp_gpio *gpio;
	struct gpio_set_config set_in;
	int ret;

	gpio = gpiochip_get_data(gc);

	set_in.gpio = off + RPI_EXP_GPIO_BASE;	/* GPIO to update */
	set_in.direction = RPI_EXP_GPIO_DIR_IN;
	set_in.term_en = 0;		/* termination disabled */
	set_in.term_pull_up = 0;	/* n/a as termination disabled */
	set_in.state = 0;		/* n/a as configured as an input */

	ret = rpi_exp_gpio_get_polarity(gc, off);
	if (ret < 0)
		return ret;
	set_in.polarity = ret;		/* Retain existing setting */

	ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_CONFIG,
				    &set_in, sizeof(set_in));
	if (ret || set_in.gpio != 0) {
		dev_err(gc->parent, "Failed to set GPIO %u to input (%d %x)\n",
			off, ret, set_in.gpio);
		return ret ? ret : -EIO;
	}
	return 0;
}

static int rpi_exp_gpio_dir_out(struct gpio_chip *gc, unsigned int off, int val)
{
	struct rpi_exp_gpio *gpio;
	struct gpio_set_config set_out;
	int ret;

	gpio = gpiochip_get_data(gc);

	set_out.gpio = off + RPI_EXP_GPIO_BASE;	/* GPIO to update */
	set_out.direction = RPI_EXP_GPIO_DIR_OUT;
	set_out.term_en = 0;		/* n/a as an output */
	set_out.term_pull_up = 0;	/* n/a as termination disabled */

Annotation

Implementation Notes