[U-Boot] [PATCH 06/10] PINCTRL: stm32f7: add pin control driver

Simon Glass sjg at chromium.org
Fri Feb 10 16:22:20 UTC 2017


Hi Vikas,

On 4 February 2017 at 15:43, Vikas Manocha <vikas.manocha at st.com> wrote:
> This driver uses the same pin control binding as that of linux, binding
> document of this patch is copied from linux. One addition done is for
> GPIO input and output mode configuration which was missing.
>
> Signed-off-by: Vikas Manocha <vikas.manocha at st.com>
> ---
>  configs/stm32f746-disco_defconfig                  |   3 +
>  .../pinctrl/st,stm32-pinctrl.txt                   | 133 +++++++++++++++++++++
>  drivers/pinctrl/Kconfig                            |   9 ++
>  drivers/pinctrl/Makefile                           |   1 +
>  drivers/pinctrl/pinctrl_stm32.c                    | 118 ++++++++++++++++++
>  5 files changed, 264 insertions(+)
>  create mode 100644 doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt
>  create mode 100644 drivers/pinctrl/pinctrl_stm32.c

Reviewed-by: Simon Glass <sjg at chromium.org>

nits below

>
> diff --git a/configs/stm32f746-disco_defconfig b/configs/stm32f746-disco_defconfig
> index af1449c..e77ebfc 100644
> --- a/configs/stm32f746-disco_defconfig
> +++ b/configs/stm32f746-disco_defconfig
> @@ -39,3 +39,6 @@ CONFIG_STM32_QSPI=y
>  CONFIG_OF_LIBFDT_OVERLAY=y
>  # CONFIG_EFI_LOADER is not set
>  CONFIG_CLK=y
> +CONFIG_PINCTRL=y
> +# CONFIG_PINCTRL_FULL is not set
> +CONFIG_PINCTRL_STM32=y
> diff --git a/doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt b/doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt
> new file mode 100644
> index 0000000..c41ae91
> --- /dev/null
> +++ b/doc/device-tree-bindings/pinctrl/st,stm32-pinctrl.txt
> @@ -0,0 +1,133 @@
> +* STM32 GPIO and Pin Mux/Config controller
> +
> +STMicroelectronics's STM32 MCUs intregrate a GPIO and Pin mux/config hardware
> +controller. It controls the input/output settings on the available pins and
> +also provides ability to multiplex and configure the output of various on-chip
> +controllers onto these pads.
> +
> +Pin controller node:
> +Required properies:
> + - compatible: value should be one of the following:
> +   (a) "st,stm32f429-pinctrl"
> +   (b) "st,stm32f746-pinctrl"
> + - #address-cells: The value of this property must be 1
> + - #size-cells : The value of this property must be 1
> + - ranges      : defines mapping between pin controller node (parent) to
> +   gpio-bank node (children).
> + - pins-are-numbered: Specify the subnodes are using numbered pinmux to
> +   specify pins.
> +
> +GPIO controller/bank node:
> +Required properties:
> + - gpio-controller : Indicates this device is a GPIO controller
> + - #gpio-cells   : Should be two.
> +                       The first cell is the pin number
> +                       The second one is the polarity:
> +                               - 0 for active high
> +                               - 1 for active low
> + - reg           : The gpio address range, relative to the pinctrl range
> + - clocks        : clock that drives this bank
> + - st,bank-name          : Should be a name string for this bank as specified in
> +   the datasheet
> +
> +Optional properties:
> + - reset:        : Reference to the reset controller
> + - interrupt-parent: phandle of the interrupt parent to which the external
> +   GPIO interrupts are forwarded to.
> + - st,syscfg: Should be phandle/offset pair. The phandle to the syscon node
> +   which includes IRQ mux selection register, and the offset of the IRQ mux
> +   selection register.
> +
> +Example:
> +#include <dt-bindings/pinctrl/stm32f429-pinfunc.h>
> +...
> +
> +       pin-controller {
> +               #address-cells = <1>;
> +               #size-cells = <1>;
> +               compatible = "st,stm32f429-pinctrl";
> +               ranges = <0 0x40020000 0x3000>;
> +               pins-are-numbered;
> +
> +               gpioa: gpio at 40020000 {
> +                       gpio-controller;
> +                       #gpio-cells = <2>;
> +                       reg = <0x0 0x400>;
> +                       resets = <&reset_ahb1 0>;
> +                       st,bank-name = "GPIOA";
> +               };
> +               ...
> +               pin-functions nodes follow...
> +       };
> +
> +Contents of function subnode node:
> +----------------------------------
> +Subnode format
> +A pinctrl node should contain at least one subnode representing the
> +pinctrl group available on the machine. Each subnode will list the
> +pins it needs, and how they should be configured, with regard to muxer
> +configuration, pullups, drive, output high/low and output speed.
> +
> +    node {
> +       pinmux = <PIN_NUMBER_PINMUX>;
> +       GENERIC_PINCONFIG;
> +    };
> +
> +Required properties:
> +- pinmux: integer array, represents gpio pin number and mux setting.
> +  Supported pin number and mux varies for different SoCs, and are defined in
> +  dt-bindings/pinctrl/<soc>-pinfunc.h directly.
> +  These defines are calculated as:
> +    ((port * 16 + line) << 8) | function
> +  With:
> +    - port: The gpio port index (PA = 0, PB = 1, ..., PK = 11)
> +    - line: The line offset within the port (PA0 = 0, PA1 = 1, ..., PA15 = 15)
> +    - function: The function number, can be:
> +      * 0 : GPIO IN
> +      * 1 : Alternate Function 0
> +      * 2 : Alternate Function 1
> +      * 3 : Alternate Function 2
> +      * ...
> +      * 16 : Alternate Function 15
> +      * 17 : Analog
> +      * 18 : GPIO OUT
> +
> +Optional properties:
> +- GENERIC_PINCONFIG: is the generic pinconfig options to use.
> +  Available options are:
> +   - bias-disable,
> +   - bias-pull-down,
> +   - bias-pull-up,
> +   - drive-push-pull,
> +   - drive-open-drain,
> +   - output-low
> +   - output-high
> +   - slew-rate = <x>, with x being:
> +       < 0 > : Low speed
> +       < 1 > : Medium speed
> +       < 2 > : Fast speed
> +       < 3 > : High speed
> +
> +Example:
> +
> +pin-controller {
> +...
> +       usart1_pins_a: usart1 at 0 {
> +               pins1 {
> +                       pinmux = <STM32F429_PA9_FUNC_USART1_TX>;
> +                       bias-disable;
> +                       drive-push-pull;
> +                       slew-rate = <0>;
> +               };
> +               pins2 {
> +                       pinmux = <STM32F429_PA10_FUNC_USART1_RX>;
> +                       bias-disable;
> +               };
> +       };
> +};
> +
> +&usart1 {
> +       pinctrl-0 = <&usart1_pins_a>;
> +       pinctrl-names = "default";
> +       status = "okay";
> +};
> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
> index efcb4c0..2dc420c 100644
> --- a/drivers/pinctrl/Kconfig
> +++ b/drivers/pinctrl/Kconfig
> @@ -175,6 +175,15 @@ config PIC32_PINCTRL
>           by a device tree node which contains both GPIO defintion and pin control
>           functions.
>
> +config PINCTRL_STM32
> +       bool "ST STM32 pin control driver"
> +       depends on DM
> +       help
> +         Supports pin multiplexing control on stm32 SoCs. The driver is
> +         controlled by a device tree node which contains both the GPIO
> +         definitions and pin control functions for each available multiplex
> +         function.
> +
>  endif
>
>  source "drivers/pinctrl/meson/Kconfig"
> diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
> index 512112a..2e23b05 100644
> --- a/drivers/pinctrl/Makefile
> +++ b/drivers/pinctrl/Makefile
> @@ -16,3 +16,4 @@ obj-$(CONFIG_PIC32_PINCTRL)   += pinctrl_pic32.o
>  obj-$(CONFIG_PINCTRL_EXYNOS)   += exynos/
>  obj-$(CONFIG_PINCTRL_MESON)    += meson/
>  obj-$(CONFIG_PINCTRL_MVEBU)    += mvebu/
> +obj-$(CONFIG_PINCTRL_STM32)    += pinctrl_stm32.o
> diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c
> new file mode 100644
> index 0000000..c794056
> --- /dev/null
> +++ b/drivers/pinctrl/pinctrl_stm32.c
> @@ -0,0 +1,118 @@
> +#include <common.h>
> +#include <asm/arch/gpio.h>
> +#include <dm.h>
> +#include <dm/pinctrl.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +static int prep_gpio_dsc(struct stm32_gpio_dsc *gpio_dsc, u32 port_pin)
> +{
> +       gpio_dsc->port = (port_pin & 0xF000) >> 12;
> +       gpio_dsc->pin = (port_pin & 0x0F00) >> 8;
> +       debug("%s: GPIO:port= %d, pin= %d\n", __func__, gpio_dsc->port,
> +             gpio_dsc->pin);

blank line

> +       return 0;
> +}
> +
> +static int prep_gpio_ctl(struct stm32_gpio_ctl *gpio_ctl, u32 gpio_fn, int node)
> +{
> +       gpio_fn &= 0x00FF;
> +
> +       switch (gpio_fn) {
> +       case 0:
> +               gpio_ctl->mode = STM32_GPIO_MODE_IN;
> +               break;
> +       case 1 ... 16:
> +               gpio_ctl->mode = STM32_GPIO_MODE_AF;
> +               gpio_ctl->af = gpio_fn - 1;
> +               break;
> +       case 17:
> +               gpio_ctl->mode = STM32_GPIO_MODE_AN;
> +               break;
> +       default:
> +               gpio_ctl->mode = STM32_GPIO_MODE_OUT;
> +               break;
> +       }
> +
> +       gpio_ctl->speed = fdtdec_get_int(gd->fdt_blob, node, "slew-rate", 0);
> +
> +       if (fdtdec_get_bool(gd->fdt_blob, node, "drive-open-drain"))
> +               gpio_ctl->otype = STM32_GPIO_OTYPE_OD;
> +       else
> +               gpio_ctl->otype = STM32_GPIO_OTYPE_PP;
> +
> +       if (fdtdec_get_bool(gd->fdt_blob, node, "bias-pull-up"))
> +               gpio_ctl->pupd = STM32_GPIO_PUPD_UP;
> +       else if (fdtdec_get_bool(gd->fdt_blob, node, "bias-pull-down"))
> +               gpio_ctl->pupd = STM32_GPIO_PUPD_DOWN;
> +       else
> +               gpio_ctl->pupd = STM32_GPIO_PUPD_NO;
> +
> +       debug("%s: gpio fn= %d, slew-rate= %x, op type= %x, pull-upd is = %x\n",
> +             __func__,  gpio_fn, gpio_ctl->speed, gpio_ctl->otype,
> +            gpio_ctl->pupd);

blank line

> +       return 0;
> +}
> +
> +static int stm32_pinctrl_set_state_simple(struct udevice *dev,
> +                                         struct udevice *periph)
> +{
> +       u32 pin_mux[50];
> +       struct fdtdec_phandle_args args;
> +       int rv, len;
> +
> +       /* Get node pinctrl-0 */
> +       rv = fdtdec_parse_phandle_with_args(gd->fdt_blob, periph->of_offset,
> +                                          "pinctrl-0", 0, 0, 0, &args);
> +       if (rv)
> +               return rv;
> +       /* check for "pinmux" property in each subnode (e.g. pins1 and pins2 for
> +        * usart1) of pin controller phandle "pinctrl-0" */
> +       fdt_for_each_subnode(args.node, gd->fdt_blob, args.node) {
> +               struct stm32_gpio_dsc gpio_dsc;
> +               struct stm32_gpio_ctl gpio_ctl;
> +               int i;

blank line

> +               /* just to get the length of "pinmux" to allocate
> +                * correct size or memory */

/*
 * Just to get the ...
 * ...
 */

also try to use more of the columns

> +               fdt_get_property(gd->fdt_blob, args.node, "pinmux", &len);
> +               len /= 4;
> +               debug("%s: no of pinmux entries= %d\n", __func__, len);
> +               rv = fdtdec_get_int_array(gd->fdt_blob, args.node,
> +                                                "pinmux", pin_mux, len);

Can you use fdtdec_get_int_array_count() ?

> +               if (rv)
> +                       return rv;

return -EINVAL

since rv will contain an FDT error (different values)

> +               for (i = 0; i < len; i++) {
> +                       debug("%s: pinmux = %x\n", __func__, *(pin_mux + i));
> +                       prep_gpio_dsc(&gpio_dsc, *(pin_mux + i));
> +                       prep_gpio_ctl(&gpio_ctl, *(pin_mux + i), args.node);
> +
> +                       rv = stm32_gpio_config(&gpio_dsc, &gpio_ctl);
> +                       debug("%s: rv = %d\n\n", __func__, rv);
> +                       if (rv)
> +                               return rv;
> +               }
> +       }
> +       return 0;
> +}
> +
> +static int stm32_pinctrl_probe(struct udevice *dev)
> +{
> +       return 0;
> +}

drop this function?

> +static struct pinctrl_ops stm32_pinctrl_ops = {
> +       .set_state_simple       = stm32_pinctrl_set_state_simple,
> +};
> +
> +static const struct udevice_id stm32_pinctrl_ids[] = {
> +       { .compatible = "st,stm32f746-pinctrl" },
> +       { }
> +};
> +
> +U_BOOT_DRIVER(pinctrl_stm32) = {
> +       .name           = "pinctrl_stm32",
> +       .id             = UCLASS_PINCTRL,
> +       .of_match       = stm32_pinctrl_ids,
> +       .ops            = &stm32_pinctrl_ops,
> +       .probe          = stm32_pinctrl_probe,
> +       .bind           = dm_scan_fdt_dev,
> +};
> --
> 1.9.1
>

Regards,
Simon


More information about the U-Boot mailing list