# Port multiplexer configuration and GPIO API overview

On AVR chips, most external I/O pins are routed through a port multiplexer. There are currently two kinds of port multiplexer hardware around with different register interfaces:

- PIO (AT32AP700x; also used on ARM AT91 chips)
- GPIO (all other AVR32 chips)

The "PIO" variant supports multiplexing up to two peripherals per pin in addition to GPIO (software control). Each pin has configurable pull-up, glitch filter, interrupt and multi-drive capabilities.

The "GPIO" variant supports multiplexing up to four peripherals per pin in addition to GPIO. Each pin has configurable pull-up/pull-down/buskeeper, glitch filter, interrupt, open-drain and schmitt-trigger capabilities, as well as configurable drive strength and slew rate control.

Both controllers are configured using the same API, but the functions may accept different values for some parameters depending on the actual portmux implementation, and some parameters may be ignored by one of the implementation (e.g. the "PIO" implementation will ignore the drive strength flags since the hardware doesn't support configurable drive strength.)

## Identifying Pins

The portmux configuration functions described below identify the pins to act on based on two parameters: A "port" (i.e. a block of pins that somehow belong together) and a pin mask. Both are defined in an implementation-specific manner.

The available ports are defined on the form

     #define PORTMUX_PORT_A (something)

where "A" matches the identifier given in the chip's data sheet, and "something" is whatever the portmux implementation needs to identify the port (usually a memory address).

The pin mask is a bitmask of type pin_mask_t, where each '1' bit indicates a pin to apply the current operation to. The width of the bitmask is implementation specific, but it's usually 32 bits on 32-bit architectures.

## Selecting Functions

Each pin can either be assigned to one of a predefined set of on-chip peripherals, or it can be set up to be controlled by software. For the former case, the portmux implementation defines an enum containing all the possible peripheral functions that can be selected. For example, the PIO implementation, which allows multiplexing two peripherals per pin, defines it like this:

     enum portmux_function {
            PORTMUX_FUNC_A,
            PORTMUX_FUNC_B,
     };

To configure a set of pins to be connected to a given peripheral function, the following function is used.

     void portmux_select_peripheral(void *port, pin_mask_t pin_mask,
                    enum portmux_function func, unsigned long flags);

To configure a set of pins to be controlled by software (GPIO), the following function is used. In this case, no "function" argument is required since "GPIO" is a function in its own right.

     void portmux_select_gpio(void *port, pin_mask_t pin_mask,
                    unsigned long flags);

Both of these functions take a "flags" parameter which may be used to alter the default configuration of the pin. This is a bitmask of various flags defined in an implementation-specific way, but the names of the flags are the same on all implementations.

### Flags indicating pin direction

The following flags specify the direction of a GPIO pin. They are mutually exclusive and only valid when setting up a pin for software control (GPIO):

- `PORTMUX_DIR_OUTPUT:` Output pin. Setting this flag enables the output driver.
- `PORTMUX_DIR_INPUT:` Input pin. Setting this flag disables the output driver.

### Flags indicating initial pin state

The following flags specify the initial state of a GPIO output pin. They are mutually exclusive and only valid when setting up a GPIO pin with the PORTMUX_DIR_OUTPUT flag set.

- `PORTMUX_INIT_HIGH:` Drive the pin high (Vdd) initially.
- `PORTMUX_INIT_LOW:` Drive the pin low (Vss) initially.

### Flags indicating pull-up/pull-down state

The following flags specify the state of the on-chip CMOS resistors connected to the pins. They are mutually exclusive and valid regardless of any other pin configuration properties.

Note that some portmux implementations may not support all of these flags. If PORTMUX_BUSKEEPER is specified but not supported by the hardware, the driver may enable a pull-up instead. If PORTMUX_PULL_DOWN is specified but not supported by the hardware, it will be ignored.

- `PORTMUX_PULL_UP:` Weak pull-up to Vdd
- `PORTMUX_PULL_DOWN:` Weak pull-down to Vss
- `PORTMUX_BUSKEEPER:` Enable pull-up or pull-down depending on the state of the pin when it is released. This will prevent the pin from toggling.

### Flags indicating drive strength

The following mutually-exlusive flags determine the drive strength of the pins, if supported. If the hardware doesn't support configurable drive strength, these flags are ignored.

- `PORTMUX_DRIVE_MIN:` Minimum drive strength. This will give low power consumption, but may cause corruption of high-speed signals.
- `PORTMUX_DRIVE_LOW:` Low drive strength. Somewhat higher power consumption, but tolerates higher speed.
- `PORTMUX_DRIVE_HIGH:` High drive strength. Higher power consumption, can handle higher speeds.
- `PORTMUX_DRIVE_MAX:` Maximum drive strength. Highest power consumption, but can handle very high-speed signals.

Note that setting the drive strength too high may cause excessive overshoot and EMI problems, which may in turn cause signal corruption.

### Flags for supporting open-drain busses

The following flag will configure the pins as "open drain", i.e. setting the pin state to 0 will drive it low, while setting it to 1 will leave it floating (in most cases, an external or internal pull-up resistor will ensure it goes high.)

This mode is also known as "multi-drive" mode.

- `PORTMUX_OPEN_DRAIN`

## Enabling specific peripherals

In addition to the above functions, each chip provides a set of functions for setting up the port multiplexer to use a given peripheral. The following functions are available, if the selected chip supports the corresponding feature:

- portmux_enable_ebi():
- portmux_enable_usart(): Configure the portmux to enable a given USART.
- portmux_enable_usbb(): Configure the portmux to enable the USBB controller.
- portmux_enable_macb():
- portmux_enable_mmci():
- portmux_enable_spi(): Configure the portmux to enable a given SPI controller.

All of these functions take a drive_strength parameter, which must be one of the `PORTMUX_DRIVE_x` flags specified above. Any other portmux flags will be silently filtered out.

## Using GPIO

Once a pin has been set up as a GPIO, you can, depending on how it was configured, drive it to a specific state or read the current state of the pin. The following functions are available for this purpose:

     void gpio_set_value(unsigned int pin, bool value);
     bool gpio_get_value(unsigned int pin);