Skip to content

gpio/pinctrl: GPIO and introduce PINCTRL API to support gpio, pinctrl DTS nodes #15611

@mnkp

Description

@mnkp

Introduction

As a general requirement we want Zephyr DTS to adhere to the specification as well as to use bindings compatible with those of the Linux kernel. To support gpio, pinctrl DTS node bindings the current GPIO driver needs to be reworked. We also need to introduce PINCTRL driver.

A GPIO driver is used to configure and control the pins directly by the application. A PINCTRL driver is used to configure the pins and route the signals to the internal hardware modules on the SoC.

Requirement to support gpio, pinctrl DTS node bindings used by the Linux kernel doesn't imply that we have to provide the same GPIO, PINCTRL API like Linux does. In fact, the APIs can be quite different. We only need to process configuration data provided by the gpio, pinctrl DTS nodes in an easy and convenient manner.

Problem description

Unlike virtually any other driver e.g. I2C, RTC, CAN, UART which functionality is confined to a single hardware module the pin configuration and control functions can be spread among multiple SoC components. The implementation can vary significantly between vendors or even SoC families.

As an example both Intel Quark and NXP/Freescale K64 have separate GPIO and pinctrl modules however functionality assigned to each module by the respective SoC family is quite different. I.e. in one case debouncing is controlled by GPIO in the other by pinctrl module.

Pin functions controlled by

Intel Quark GPIO module: value, direction, interrupts, debouncing, source (pio/ext)
Intel Quark pinctrl module: muxing, pullup, slew rate

K64 GPIO module: value, direction
K64 pinctrl module: muxing, pullup/pulldown, slew rate, open drain, drive strength, interrupts, debouncing, source (pio/ext)

Proposed change

The driver API should hide implementation details and make it possible to write portable code. I.e. it would be impractical to expect user writing application code to know if they need to use PINCTRL or GPIO driver to configure an output as an open drain. As such both GPIO and PINCTRL API should provide means to fully configure pin properties such as open drain, drive strength, input debounce, pull up or schmitt-trigger mode.

Update GPIO and introduce PINCTRL API to let Zephyr drivers and application code configure pins using data provided by gpio, pinctrl DTS nodes. The API should use naming convention / configuration options which directly relate to the gpio, (gpio.h) and pinctrl bindings defined by Linux DTS. Zephyr implementation should preserve the meaning of Linux defined configuration options. E.g. relation between DTS pinctrl node property drive-open-drain and corresponding feature of the Zephyr API should be straightforward to identify and have the same effect.

Detailed RFC

GPIO/PINCTRL driver should use the following flags as a parameter to *_configure function:

  • GPIO_ACTIVE_LOW, GPIO_ACTIVE_HIGH: indicate pin active state (logical value '1' in low state or logical value '1' in high state). gpio_pin_write/gpio_pin_read functions should write/read the logical pin value.
  • GPIO_OPEN_DRAIN, GPIO_OPEN_SOURCE: configure single ended pin driving mode
  • GPIO_PULL_UP, GPIO_PULL_DOWN: enable pin pull-up, pull-down
  • GPIO_INPUT: configure pin as input
  • GPIO_OUTPUT: configure pin as output. By default output is configured in push/pull mode. This behavior can be modified via GPIO_OPEN_DRAIN, GPIO_OPEN_SOURCE flags.
  • GPIO_OUTPUT_INIT_LOW/GPIO_OUTPUT_INIT_HIGH: initialize the output in a low/high state
  • GPIO_INPUT_DEBOUNCE: enable pin debounce circuitry

Linux DTS does not specify interrupt configuration within GPIO/PINCTRL node but rather a dedicated IRQ chip node. Zephyr GPIO API shall provide means to directly configure interrupts. Following base flags are proposed:

  • GPIO_INT_ENABLE
  • GPIO_INT_LEVEL
  • GPIO_INT_EDGE
  • GPIO_INT_LOW
  • GPIO_INT_HIGH

To make interrupt configuration easier for the end user the following convenience flags are proposed:

  • GPIO_INT_EDGE_RISING
  • GPIO_INT_EDGE_FALLING
  • GPIO_INT_EDGE_BOTH
  • GPIO_INT_LEVEL_LOW
  • GPIO_INT_LEVEL_HIGH

Where each of the convenience flags is defined as a combination of a base flag. E.g.

/** Trigger GPIO pin interrupt on level high. */
#define GPIO_INT_LEVEL_HIGH     (GPIO_INT_ENABLE  \
				 | GPIO_INT_LEVEL \
				 | GPIO_INT_HIGH)

New API functions

Following two functions are added to let the user directly control the pin level ignoring GPIO_ACTIVE_LOW flag. Writing value 1 to a pin will always set it to high output state, writing value 0 will always set it to low output state.

int gpio_pin_write_raw(struct device *port, u32_t pin, u32_t value);
int gpio_pin_read_raw(struct device *port, u32_t pin, u32_t *value);

Pin Controller API: TBD

Dependencies

When a new PINCTRL API is introduced the current PINMUX API can be deprecated.

Concerns and Unresolved Questions

The GPIO and PINCTRL drivers will significantly overlap their functionality since many driver features (e.g. pin drive strength, pull-up, pull-down, ability to configure output as on open source) need to be provided by both drivers. A better choice may be merging the two APIs into one.

Metadata

Metadata

Assignees

No one assigned

    Labels

    RFCRequest For Comments: want input from the communityarea: APIChanges to public APIsarea: GPIO

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions