diff --git a/drivers/pinctrl/pinctrl-stm32.c b/drivers/pinctrl/pinctrl-stm32.c index c199d74..cdaed51 100644 --- a/drivers/pinctrl/pinctrl-stm32.c +++ b/drivers/pinctrl/pinctrl-stm32.c @@ -87,110 +87,128 @@ return 0; } -static int stm32_pinctrl_set_state(struct pinctrl_device *pdev, struct device_node *group) +static int __stm32_pinctrl_set_state(struct device_d *dev, struct device_node *pins) +{ + int ret; + + int num_pins = 0, i; + u32 slew_rate; + bool adjust_slew_rate = false; + enum stm32_pin_bias bias = -1; + enum stm32_pin_out_type out_type = -1; + enum { PIN_INPUT, PIN_OUTPUT_LOW, PIN_OUTPUT_HIGH } dir = -1; + + of_get_property(pins, "pinmux", &num_pins); + num_pins /= sizeof(__be32); + if (!num_pins) { + dev_err(dev, "Invalid pinmux property in %s\n", + pins->full_name); + return -EINVAL; + } + + ret = of_property_read_u32(pins, "slew-rate", &slew_rate); + if (!ret) + adjust_slew_rate = true; + + if (of_get_property(pins, "bias-disable", NULL)) + bias = STM32_PIN_NO_BIAS; + else if (of_get_property(pins, "bias-pull-up", NULL)) + bias = STM32_PIN_PULL_UP; + else if (of_get_property(pins, "bias-pull-down", NULL)) + bias = STM32_PIN_PULL_DOWN; + + if (of_get_property(pins, "drive-push-pull", NULL)) + out_type = STM32_PIN_OUT_PUSHPULL; + else if (of_get_property(pins, "drive-open-drain", NULL)) + out_type = STM32_PIN_OUT_OPENDRAIN; + + if (of_get_property(pins, "input-enable", NULL)) + dir = PIN_INPUT; + else if (of_get_property(pins, "output-low", NULL)) + dir = PIN_OUTPUT_LOW; + else if (of_get_property(pins, "output-high", NULL)) + dir = PIN_OUTPUT_HIGH; + + dev_dbg(dev, "%s: multiplexing %d pins\n", pins->full_name, num_pins); + + for (i = 0; i < num_pins; i++) { + struct stm32_gpio_bank *bank = NULL; + u32 pinfunc, mode, alt; + unsigned func; + int offset; + + ret = of_property_read_u32_index(pins, "pinmux", + i, &pinfunc); + if (ret) + return ret; + + func = STM32_GET_PIN_FUNC(pinfunc); + offset = stm32_gpio_pin(STM32_GET_PIN_NO(pinfunc), &bank); + if (offset < 0) + return -ENODEV; + + mode = stm32_gpio_get_mode(func); + alt = stm32_gpio_get_alt(func); + + dev_dbg(dev, "configuring port %s pin %u with:\n\t" + "fn %u, mode %u, alt %u\n", + bank->name, offset, func, mode, alt); + + clk_enable(bank->clk); + + __stm32_pmx_set_mode(bank->base, offset, mode, alt); + + if (adjust_slew_rate) + __stm32_pmx_set_speed(bank->base, offset, slew_rate); + + if (bias != -1) + __stm32_pmx_set_bias(bank->base, offset, bias); + + if (out_type != -1) + __stm32_pmx_set_output_type(bank->base, offset, out_type); + + if (dir == PIN_INPUT) + __stm32_pmx_gpio_input(bank->base, offset); + else if (dir == PIN_OUTPUT_LOW) + __stm32_pmx_gpio_output(bank->base, offset, 0); + else if (dir == PIN_OUTPUT_HIGH) + __stm32_pmx_gpio_output(bank->base, offset, 1); + + clk_disable(bank->clk); + } + + return 0; +} + +static int stm32_pinctrl_set_state(struct pinctrl_device *pdev, struct device_node *np) { struct stm32_pinctrl *pinctrl = to_stm32_pinctrl(pdev); + struct device_d *dev = pdev->dev; struct device_node *pins; + void *prop; int ret; ret = hwspinlock_lock_timeout(&pinctrl->hws, 10); if (ret == -ETIMEDOUT) { - dev_err(pdev->dev, "hw spinlock timeout\n"); + dev_err(dev, "hw spinlock timeout\n"); return ret; } - for_each_child_of_node(group, pins) { - int num_pins = 0, i; - u32 slew_rate; - bool adjust_slew_rate = false; - enum stm32_pin_bias bias = -1; - enum stm32_pin_out_type out_type = -1; - enum { PIN_INPUT, PIN_OUTPUT_LOW, PIN_OUTPUT_HIGH } dir = -1; - - of_get_property(pins, "pinmux", &num_pins); - num_pins /= sizeof(__be32); - if (!num_pins) { - dev_err(pdev->dev, "Invalid pinmux property in %s\n", - pins->full_name); - return -EINVAL; - } - - ret = of_property_read_u32(pins, "slew-rate", &slew_rate); - if (!ret) - adjust_slew_rate = true; - - if (of_get_property(pins, "bias-disable", NULL)) - bias = STM32_PIN_NO_BIAS; - else if (of_get_property(pins, "bias-pull-up", NULL)) - bias = STM32_PIN_PULL_UP; - else if (of_get_property(pins, "bias-pull-down", NULL)) - bias = STM32_PIN_PULL_DOWN; - - if (of_get_property(pins, "drive-push-pull", NULL)) - out_type = STM32_PIN_OUT_PUSHPULL; - else if (of_get_property(pins, "drive-open-drain", NULL)) - out_type = STM32_PIN_OUT_OPENDRAIN; - - if (of_get_property(pins, "input-enable", NULL)) - dir = PIN_INPUT; - else if (of_get_property(pins, "output-low", NULL)) - dir = PIN_OUTPUT_LOW; - else if (of_get_property(pins, "output-high", NULL)) - dir = PIN_OUTPUT_HIGH; - - dev_dbg(pdev->dev, "%s: multiplexing %d pins\n", - pins->full_name, num_pins); - - for (i = 0; i < num_pins; i++) { - struct stm32_gpio_bank *bank = NULL; - u32 pinfunc, mode, alt; - unsigned func; - int offset; - - ret = of_property_read_u32_index(pins, "pinmux", - i, &pinfunc); - if (ret) - return ret; - - func = STM32_GET_PIN_FUNC(pinfunc); - offset = stm32_gpio_pin(STM32_GET_PIN_NO(pinfunc), &bank); - if (offset < 0) - return -ENODEV; - - mode = stm32_gpio_get_mode(func); - alt = stm32_gpio_get_alt(func); - - dev_dbg(pdev->dev, "configuring port %s pin %u with:\n\t" - "fn %u, mode %u, alt %u\n", - bank->name, offset, func, mode, alt); - - clk_enable(bank->clk); - - __stm32_pmx_set_mode(bank->base, offset, mode, alt); - - if (adjust_slew_rate) - __stm32_pmx_set_speed(bank->base, offset, slew_rate); - - if (bias != -1) - __stm32_pmx_set_bias(bank->base, offset, bias); - - if (out_type != -1) - __stm32_pmx_set_output_type(bank->base, offset, out_type); - - if (dir == PIN_INPUT) - __stm32_pmx_gpio_input(bank->base, offset); - else if (dir == PIN_OUTPUT_LOW) - __stm32_pmx_gpio_output(bank->base, offset, 0); - else if (dir == PIN_OUTPUT_HIGH) - __stm32_pmx_gpio_output(bank->base, offset, 1); - - clk_disable(bank->clk); - } + prop = of_find_property(np, "pinmux", NULL); + if (prop) { + ret = __stm32_pinctrl_set_state(dev, np); + goto out; } - hwspinlock_unlock(&pinctrl->hws); + for_each_child_of_node(np, pins) { + ret = __stm32_pinctrl_set_state(dev, pins); + if (ret) + goto out; + } - return 0; +out: + hwspinlock_unlock(&pinctrl->hws); + return ret; } /* GPIO functions */