// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2015 Maxime Coquelin * Copyright (C) 2017 STMicroelectronics * Copyright (C) 2019 Ahmad Fatoum, Pengutronix */ #include #include #include #include #include #include #include #include #include #include #include #define STM32_PIN_NO(x) ((x) << 8) #define STM32_GET_PIN_NO(x) ((x) >> 8) #define STM32_GET_PIN_FUNC(x) ((x) & 0xff) struct stm32_gpio_bank { void __iomem *base; struct gpio_chip chip; struct clk *clk; const char *name; }; struct stm32_pinctrl { struct pinctrl_device pdev; struct hwspinlock hws; struct stm32_gpio_bank gpio_banks[]; }; static inline struct stm32_pinctrl *to_stm32_pinctrl(struct pinctrl_device *pdev) { return container_of(pdev, struct stm32_pinctrl, pdev); } static inline struct stm32_gpio_bank *to_stm32_gpio_bank(struct gpio_chip *chip) { return container_of(chip, struct stm32_gpio_bank, chip); } static inline int stm32_gpio_pin(int gpio, struct stm32_gpio_bank **bank) { if (bank) { struct gpio_chip *chip; chip = gpio_get_chip(gpio); if (!chip) return -EINVAL; *bank = to_stm32_gpio_bank(chip); } return gpio % STM32_GPIO_PINS_PER_BANK; } static inline u32 stm32_gpio_get_mode(u32 function) { switch (function) { case STM32_PIN_GPIO: return 0; case STM32_PIN_AF(0) ... STM32_PIN_AF(15): return 2; case STM32_PIN_ANALOG: return 3; } return 0; } static inline u32 stm32_gpio_get_alt(u32 function) { switch (function) { case STM32_PIN_GPIO: return 0; case STM32_PIN_AF(0) ... STM32_PIN_AF(15): return function - 1; case STM32_PIN_ANALOG: return 0; } return 0; } 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(dev, "hw spinlock timeout\n"); return ret; } prop = of_find_property(np, "pinmux", NULL); if (prop) { ret = __stm32_pinctrl_set_state(dev, np); goto out; } for_each_child_of_node(np, pins) { ret = __stm32_pinctrl_set_state(dev, pins); if (ret) goto out; } out: hwspinlock_unlock(&pinctrl->hws); return ret; } /* GPIO functions */ static int stm32_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio) { struct stm32_gpio_bank *bank = to_stm32_gpio_bank(chip); int ret; u32 mode, alt; clk_enable(bank->clk); __stm32_pmx_get_mode(bank->base, stm32_gpio_pin(gpio, NULL), &mode, &alt); if ((alt == 0) && (mode == 0)) ret = 1; else if ((alt == 0) && (mode == 1)) ret = 0; else ret = -EINVAL; clk_disable(bank->clk); return ret; } static void stm32_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) { struct stm32_gpio_bank *bank = to_stm32_gpio_bank(chip); clk_enable(bank->clk); __stm32_pmx_gpio_set(bank->base, stm32_gpio_pin(gpio, NULL), value); clk_disable(bank->clk); } static int stm32_gpio_get(struct gpio_chip *chip, unsigned gpio) { struct stm32_gpio_bank *bank = to_stm32_gpio_bank(chip); int ret; clk_enable(bank->clk); ret = __stm32_pmx_gpio_get(bank->base, stm32_gpio_pin(gpio, NULL)); clk_disable(bank->clk); return ret; } static int stm32_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) { struct stm32_gpio_bank *bank = to_stm32_gpio_bank(chip); clk_enable(bank->clk); __stm32_pmx_gpio_input(bank->base, stm32_gpio_pin(gpio, NULL)); clk_disable(bank->clk); return 0; } static int stm32_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value) { struct stm32_gpio_bank *bank = to_stm32_gpio_bank(chip); clk_enable(bank->clk); __stm32_pmx_gpio_output(bank->base, stm32_gpio_pin(gpio, NULL), value); clk_disable(bank->clk); return 0; } static struct gpio_ops stm32_gpio_ops = { .direction_input = stm32_gpio_direction_input, .direction_output = stm32_gpio_direction_output, .get_direction = stm32_gpio_get_direction, .get = stm32_gpio_get, .set = stm32_gpio_set, }; static int stm32_gpiochip_add(struct stm32_gpio_bank *bank, struct device_node *np, struct device_d *parent) { struct device_d *dev; struct resource *iores; enum { PINCTRL_PHANDLE, GPIOCTRL_OFFSET, PINCTRL_OFFSET, PINCOUNT, GPIO_RANGE_NCELLS }; const __be32 *gpio_ranges; u32 ngpios; int id, ret, size; dev = of_platform_device_create(np, parent); if (!dev) return -ENODEV; gpio_ranges = of_get_property(np, "gpio-ranges", &size); size /= sizeof(__be32); if (!gpio_ranges || size < GPIO_RANGE_NCELLS) { dev_err(dev, "Couldn't read 'gpio-ranges' property in %s\n", np->full_name); return -EINVAL; } ret = of_property_read_u32(np, "ngpios", &ngpios); if (ret) ngpios = be32_to_cpu(gpio_ranges[PINCOUNT]); bank->chip.ngpio = ngpios; if (size > GPIO_RANGE_NCELLS) { dev_err(dev, "Unsupported disjunct 'gpio-ranges' in %s\n", np->full_name); return -EINVAL; } if (ngpios > STM32_GPIO_PINS_PER_BANK) { dev_err(dev, "ngpios property expected to be %u at most in %s\n", ngpios, np->full_name); return -EINVAL; } ret = of_property_read_string(np, "st,bank-name", &bank->name); if (ret) bank->name = np->name; iores = dev_request_mem_resource(dev, 0); if (IS_ERR(iores)) { dev_err(dev, "Failed to request GPIO memory resource\n"); return PTR_ERR(iores); } bank->base = IOMEM(iores->start); if (dev->id >= 0) { id = dev->id; } else { id = of_alias_get_id(np, "gpio"); if (id < 0) { dev_err(dev, "Failed to get GPIO alias\n"); return id; } } bank->chip.base = id * STM32_GPIO_PINS_PER_BANK; bank->chip.ops = &stm32_gpio_ops; bank->chip.dev = dev; bank->clk = clk_get(dev, NULL); if (IS_ERR(bank->clk)) { dev_err(dev, "failed to get clk (%ld)\n", PTR_ERR(bank->clk)); return PTR_ERR(bank->clk); } return gpiochip_add(&bank->chip); } static struct pinctrl_ops stm32_pinctrl_ops = { .set_state = stm32_pinctrl_set_state, }; static int stm32_pinctrl_probe(struct device_d *dev) { struct stm32_pinctrl *pinctrl; unsigned nbanks = 0; struct stm32_gpio_bank *gpio_bank; struct device_node *np = dev->device_node, *child; int ret; if (!of_find_property(np, "pins-are-numbered", NULL)) { dev_err(dev, "only pins-are-numbered format supported\n"); return -EINVAL; } for_each_available_child_of_node(np, child) if (of_property_read_bool(child, "gpio-controller")) nbanks++; pinctrl = xzalloc(sizeof(*pinctrl) + nbanks * sizeof(struct stm32_gpio_bank)); pinctrl->pdev.dev = dev; pinctrl->pdev.ops = &stm32_pinctrl_ops; /* hwspinlock property is optional, just log the error */ ret = hwspinlock_get_by_index(dev, 0, &pinctrl->hws); if (ret) dev_dbg(dev, "proceeding without hw spinlock support: (%d)\n", ret); ret = pinctrl_register(&pinctrl->pdev); if (ret) { dev_dbg(dev, "pinctrl_register failed: (%d)\n", ret); return ret; } gpio_bank = pinctrl->gpio_banks; for_each_available_child_of_node(np, child) { if (!of_property_read_bool(child, "gpio-controller")) continue; ret = stm32_gpiochip_add(gpio_bank++, child, dev); if (ret) { dev_err(dev, "couldn't add gpiochip %s, ret = %d\n", child->name, ret); return ret; } } dev_dbg(dev, "pinctrl/gpio driver registered\n"); return 0; } static __maybe_unused struct of_device_id stm32_pinctrl_dt_ids[] = { { .compatible = "st,stm32f429-pinctrl" }, { .compatible = "st,stm32f469-pinctrl" }, { .compatible = "st,stm32f746-pinctrl" }, { .compatible = "st,stm32h743-pinctrl" }, { .compatible = "st,stm32mp157-pinctrl" }, { .compatible = "st,stm32mp157-z-pinctrl" }, { /* sentinel */ } }; static struct driver_d stm32_pinctrl_driver = { .name = "stm32-pinctrl", .probe = stm32_pinctrl_probe, .of_compatible = DRV_OF_COMPAT(stm32_pinctrl_dt_ids), }; static int stm32_pinctrl_init(void) { return platform_driver_register(&stm32_pinctrl_driver); } core_initcall(stm32_pinctrl_init);