[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