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

vikas vikas.manocha at st.com
Fri Feb 10 21:39:19 UTC 2017


Hi Simon,

On 02/10/2017 08:22 AM, Simon Glass wrote:
> 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

ok

> 
>> +       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

ok

> 
>> +               /* 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

yes, I will do it in v2 :-)

> 
>> +               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() ?

Yes but it's almost same, the only difference being xxx_array_count is relaxed on lenght/count.
And in this case we are reading length of the property just before.

In any case, i will change it to xxx_array_count in v2.

> 
>> +               if (rv)
>> +                       return rv;
> 
> return -EINVAL
> 
> since rv will contain an FDT error (different values)

ok.

> 
>> +               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?

Yes agree.

Cheers,
Vikas

> 
>> +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