18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) Maxime Coquelin 2015 48c2ecf20Sopenharmony_ci * Copyright (C) STMicroelectronics 2017 58c2ecf20Sopenharmony_ci * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Heavily based on Mediatek's pinctrl driver 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 118c2ecf20Sopenharmony_ci#include <linux/hwspinlock.h> 128c2ecf20Sopenharmony_ci#include <linux/io.h> 138c2ecf20Sopenharmony_ci#include <linux/irq.h> 148c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/of.h> 178c2ecf20Sopenharmony_ci#include <linux/of_address.h> 188c2ecf20Sopenharmony_ci#include <linux/of_device.h> 198c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 208c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 218c2ecf20Sopenharmony_ci#include <linux/pinctrl/machine.h> 228c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 238c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h> 248c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 258c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 268c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 278c2ecf20Sopenharmony_ci#include <linux/regmap.h> 288c2ecf20Sopenharmony_ci#include <linux/reset.h> 298c2ecf20Sopenharmony_ci#include <linux/slab.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include "../core.h" 328c2ecf20Sopenharmony_ci#include "../pinconf.h" 338c2ecf20Sopenharmony_ci#include "../pinctrl-utils.h" 348c2ecf20Sopenharmony_ci#include "pinctrl-stm32.h" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define STM32_GPIO_MODER 0x00 378c2ecf20Sopenharmony_ci#define STM32_GPIO_TYPER 0x04 388c2ecf20Sopenharmony_ci#define STM32_GPIO_SPEEDR 0x08 398c2ecf20Sopenharmony_ci#define STM32_GPIO_PUPDR 0x0c 408c2ecf20Sopenharmony_ci#define STM32_GPIO_IDR 0x10 418c2ecf20Sopenharmony_ci#define STM32_GPIO_ODR 0x14 428c2ecf20Sopenharmony_ci#define STM32_GPIO_BSRR 0x18 438c2ecf20Sopenharmony_ci#define STM32_GPIO_LCKR 0x1c 448c2ecf20Sopenharmony_ci#define STM32_GPIO_AFRL 0x20 458c2ecf20Sopenharmony_ci#define STM32_GPIO_AFRH 0x24 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* custom bitfield to backup pin status */ 488c2ecf20Sopenharmony_ci#define STM32_GPIO_BKP_MODE_SHIFT 0 498c2ecf20Sopenharmony_ci#define STM32_GPIO_BKP_MODE_MASK GENMASK(1, 0) 508c2ecf20Sopenharmony_ci#define STM32_GPIO_BKP_ALT_SHIFT 2 518c2ecf20Sopenharmony_ci#define STM32_GPIO_BKP_ALT_MASK GENMASK(5, 2) 528c2ecf20Sopenharmony_ci#define STM32_GPIO_BKP_SPEED_SHIFT 6 538c2ecf20Sopenharmony_ci#define STM32_GPIO_BKP_SPEED_MASK GENMASK(7, 6) 548c2ecf20Sopenharmony_ci#define STM32_GPIO_BKP_PUPD_SHIFT 8 558c2ecf20Sopenharmony_ci#define STM32_GPIO_BKP_PUPD_MASK GENMASK(9, 8) 568c2ecf20Sopenharmony_ci#define STM32_GPIO_BKP_TYPE 10 578c2ecf20Sopenharmony_ci#define STM32_GPIO_BKP_VAL 11 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define STM32_GPIO_PINS_PER_BANK 16 608c2ecf20Sopenharmony_ci#define STM32_GPIO_IRQ_LINE 16 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define SYSCFG_IRQMUX_MASK GENMASK(3, 0) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define gpio_range_to_bank(chip) \ 658c2ecf20Sopenharmony_ci container_of(chip, struct stm32_gpio_bank, range) 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define HWSPNLCK_TIMEOUT 1000 /* usec */ 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic const char * const stm32_gpio_functions[] = { 708c2ecf20Sopenharmony_ci "gpio", "af0", "af1", 718c2ecf20Sopenharmony_ci "af2", "af3", "af4", 728c2ecf20Sopenharmony_ci "af5", "af6", "af7", 738c2ecf20Sopenharmony_ci "af8", "af9", "af10", 748c2ecf20Sopenharmony_ci "af11", "af12", "af13", 758c2ecf20Sopenharmony_ci "af14", "af15", "analog", 768c2ecf20Sopenharmony_ci}; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistruct stm32_pinctrl_group { 798c2ecf20Sopenharmony_ci const char *name; 808c2ecf20Sopenharmony_ci unsigned long config; 818c2ecf20Sopenharmony_ci unsigned pin; 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistruct stm32_gpio_bank { 858c2ecf20Sopenharmony_ci void __iomem *base; 868c2ecf20Sopenharmony_ci struct clk *clk; 878c2ecf20Sopenharmony_ci struct reset_control *rstc; 888c2ecf20Sopenharmony_ci spinlock_t lock; 898c2ecf20Sopenharmony_ci struct gpio_chip gpio_chip; 908c2ecf20Sopenharmony_ci struct pinctrl_gpio_range range; 918c2ecf20Sopenharmony_ci struct fwnode_handle *fwnode; 928c2ecf20Sopenharmony_ci struct irq_domain *domain; 938c2ecf20Sopenharmony_ci u32 bank_nr; 948c2ecf20Sopenharmony_ci u32 bank_ioport_nr; 958c2ecf20Sopenharmony_ci u32 pin_backup[STM32_GPIO_PINS_PER_BANK]; 968c2ecf20Sopenharmony_ci u8 irq_type[STM32_GPIO_PINS_PER_BANK]; 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistruct stm32_pinctrl { 1008c2ecf20Sopenharmony_ci struct device *dev; 1018c2ecf20Sopenharmony_ci struct pinctrl_dev *pctl_dev; 1028c2ecf20Sopenharmony_ci struct pinctrl_desc pctl_desc; 1038c2ecf20Sopenharmony_ci struct stm32_pinctrl_group *groups; 1048c2ecf20Sopenharmony_ci unsigned ngroups; 1058c2ecf20Sopenharmony_ci const char **grp_names; 1068c2ecf20Sopenharmony_ci struct stm32_gpio_bank *banks; 1078c2ecf20Sopenharmony_ci unsigned nbanks; 1088c2ecf20Sopenharmony_ci const struct stm32_pinctrl_match_data *match_data; 1098c2ecf20Sopenharmony_ci struct irq_domain *domain; 1108c2ecf20Sopenharmony_ci struct regmap *regmap; 1118c2ecf20Sopenharmony_ci struct regmap_field *irqmux[STM32_GPIO_PINS_PER_BANK]; 1128c2ecf20Sopenharmony_ci struct hwspinlock *hwlock; 1138c2ecf20Sopenharmony_ci struct stm32_desc_pin *pins; 1148c2ecf20Sopenharmony_ci u32 npins; 1158c2ecf20Sopenharmony_ci u32 pkg; 1168c2ecf20Sopenharmony_ci u16 irqmux_map; 1178c2ecf20Sopenharmony_ci spinlock_t irqmux_lock; 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic inline int stm32_gpio_pin(int gpio) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci return gpio % STM32_GPIO_PINS_PER_BANK; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic inline u32 stm32_gpio_get_mode(u32 function) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci switch (function) { 1288c2ecf20Sopenharmony_ci case STM32_PIN_GPIO: 1298c2ecf20Sopenharmony_ci return 0; 1308c2ecf20Sopenharmony_ci case STM32_PIN_AF(0) ... STM32_PIN_AF(15): 1318c2ecf20Sopenharmony_ci return 2; 1328c2ecf20Sopenharmony_ci case STM32_PIN_ANALOG: 1338c2ecf20Sopenharmony_ci return 3; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic inline u32 stm32_gpio_get_alt(u32 function) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci switch (function) { 1428c2ecf20Sopenharmony_ci case STM32_PIN_GPIO: 1438c2ecf20Sopenharmony_ci return 0; 1448c2ecf20Sopenharmony_ci case STM32_PIN_AF(0) ... STM32_PIN_AF(15): 1458c2ecf20Sopenharmony_ci return function - 1; 1468c2ecf20Sopenharmony_ci case STM32_PIN_ANALOG: 1478c2ecf20Sopenharmony_ci return 0; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci return 0; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic void stm32_gpio_backup_value(struct stm32_gpio_bank *bank, 1548c2ecf20Sopenharmony_ci u32 offset, u32 value) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci bank->pin_backup[offset] &= ~BIT(STM32_GPIO_BKP_VAL); 1578c2ecf20Sopenharmony_ci bank->pin_backup[offset] |= value << STM32_GPIO_BKP_VAL; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic void stm32_gpio_backup_mode(struct stm32_gpio_bank *bank, u32 offset, 1618c2ecf20Sopenharmony_ci u32 mode, u32 alt) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci bank->pin_backup[offset] &= ~(STM32_GPIO_BKP_MODE_MASK | 1648c2ecf20Sopenharmony_ci STM32_GPIO_BKP_ALT_MASK); 1658c2ecf20Sopenharmony_ci bank->pin_backup[offset] |= mode << STM32_GPIO_BKP_MODE_SHIFT; 1668c2ecf20Sopenharmony_ci bank->pin_backup[offset] |= alt << STM32_GPIO_BKP_ALT_SHIFT; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic void stm32_gpio_backup_driving(struct stm32_gpio_bank *bank, u32 offset, 1708c2ecf20Sopenharmony_ci u32 drive) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci bank->pin_backup[offset] &= ~BIT(STM32_GPIO_BKP_TYPE); 1738c2ecf20Sopenharmony_ci bank->pin_backup[offset] |= drive << STM32_GPIO_BKP_TYPE; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic void stm32_gpio_backup_speed(struct stm32_gpio_bank *bank, u32 offset, 1778c2ecf20Sopenharmony_ci u32 speed) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci bank->pin_backup[offset] &= ~STM32_GPIO_BKP_SPEED_MASK; 1808c2ecf20Sopenharmony_ci bank->pin_backup[offset] |= speed << STM32_GPIO_BKP_SPEED_SHIFT; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic void stm32_gpio_backup_bias(struct stm32_gpio_bank *bank, u32 offset, 1848c2ecf20Sopenharmony_ci u32 bias) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci bank->pin_backup[offset] &= ~STM32_GPIO_BKP_PUPD_MASK; 1878c2ecf20Sopenharmony_ci bank->pin_backup[offset] |= bias << STM32_GPIO_BKP_PUPD_SHIFT; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/* GPIO functions */ 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic inline void __stm32_gpio_set(struct stm32_gpio_bank *bank, 1938c2ecf20Sopenharmony_ci unsigned offset, int value) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci stm32_gpio_backup_value(bank, offset, value); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (!value) 1988c2ecf20Sopenharmony_ci offset += STM32_GPIO_PINS_PER_BANK; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci clk_enable(bank->clk); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci writel_relaxed(BIT(offset), bank->base + STM32_GPIO_BSRR); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci clk_disable(bank->clk); 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic int stm32_gpio_request(struct gpio_chip *chip, unsigned offset) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank = gpiochip_get_data(chip); 2108c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); 2118c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range; 2128c2ecf20Sopenharmony_ci int pin = offset + (bank->bank_nr * STM32_GPIO_PINS_PER_BANK); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci range = pinctrl_find_gpio_range_from_pin_nolock(pctl->pctl_dev, pin); 2158c2ecf20Sopenharmony_ci if (!range) { 2168c2ecf20Sopenharmony_ci dev_err(pctl->dev, "pin %d not in range.\n", pin); 2178c2ecf20Sopenharmony_ci return -EINVAL; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return pinctrl_gpio_request(chip->base + offset); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic void stm32_gpio_free(struct gpio_chip *chip, unsigned offset) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci pinctrl_gpio_free(chip->base + offset); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic int stm32_gpio_get_noclk(struct gpio_chip *chip, unsigned int offset) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank = gpiochip_get_data(chip); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return !!(readl_relaxed(bank->base + STM32_GPIO_IDR) & BIT(offset)); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int stm32_gpio_get(struct gpio_chip *chip, unsigned offset) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank = gpiochip_get_data(chip); 2388c2ecf20Sopenharmony_ci int ret; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci clk_enable(bank->clk); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci ret = stm32_gpio_get_noclk(chip, offset); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci clk_disable(bank->clk); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return ret; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic void stm32_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank = gpiochip_get_data(chip); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci __stm32_gpio_set(bank, offset, value); 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic int stm32_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci return pinctrl_gpio_direction_input(chip->base + offset); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic int stm32_gpio_direction_output(struct gpio_chip *chip, 2628c2ecf20Sopenharmony_ci unsigned offset, int value) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank = gpiochip_get_data(chip); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci __stm32_gpio_set(bank, offset, value); 2678c2ecf20Sopenharmony_ci pinctrl_gpio_direction_output(chip->base + offset); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic int stm32_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank = gpiochip_get_data(chip); 2768c2ecf20Sopenharmony_ci struct irq_fwspec fwspec; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci fwspec.fwnode = bank->fwnode; 2798c2ecf20Sopenharmony_ci fwspec.param_count = 2; 2808c2ecf20Sopenharmony_ci fwspec.param[0] = offset; 2818c2ecf20Sopenharmony_ci fwspec.param[1] = IRQ_TYPE_NONE; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci return irq_create_fwspec_mapping(&fwspec); 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic int stm32_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank = gpiochip_get_data(chip); 2898c2ecf20Sopenharmony_ci int pin = stm32_gpio_pin(offset); 2908c2ecf20Sopenharmony_ci int ret; 2918c2ecf20Sopenharmony_ci u32 mode, alt; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci stm32_pmx_get_mode(bank, pin, &mode, &alt); 2948c2ecf20Sopenharmony_ci if ((alt == 0) && (mode == 0)) 2958c2ecf20Sopenharmony_ci ret = GPIO_LINE_DIRECTION_IN; 2968c2ecf20Sopenharmony_ci else if ((alt == 0) && (mode == 1)) 2978c2ecf20Sopenharmony_ci ret = GPIO_LINE_DIRECTION_OUT; 2988c2ecf20Sopenharmony_ci else 2998c2ecf20Sopenharmony_ci ret = -EINVAL; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci return ret; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic const struct gpio_chip stm32_gpio_template = { 3058c2ecf20Sopenharmony_ci .request = stm32_gpio_request, 3068c2ecf20Sopenharmony_ci .free = stm32_gpio_free, 3078c2ecf20Sopenharmony_ci .get = stm32_gpio_get, 3088c2ecf20Sopenharmony_ci .set = stm32_gpio_set, 3098c2ecf20Sopenharmony_ci .direction_input = stm32_gpio_direction_input, 3108c2ecf20Sopenharmony_ci .direction_output = stm32_gpio_direction_output, 3118c2ecf20Sopenharmony_ci .to_irq = stm32_gpio_to_irq, 3128c2ecf20Sopenharmony_ci .get_direction = stm32_gpio_get_direction, 3138c2ecf20Sopenharmony_ci .set_config = gpiochip_generic_config, 3148c2ecf20Sopenharmony_ci}; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic void stm32_gpio_irq_trigger(struct irq_data *d) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank = d->domain->host_data; 3198c2ecf20Sopenharmony_ci int level; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* Do not access the GPIO if this is not LEVEL triggered IRQ. */ 3228c2ecf20Sopenharmony_ci if (!(bank->irq_type[d->hwirq] & IRQ_TYPE_LEVEL_MASK)) 3238c2ecf20Sopenharmony_ci return; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* If level interrupt type then retrig */ 3268c2ecf20Sopenharmony_ci level = stm32_gpio_get_noclk(&bank->gpio_chip, d->hwirq); 3278c2ecf20Sopenharmony_ci if ((level == 0 && bank->irq_type[d->hwirq] == IRQ_TYPE_LEVEL_LOW) || 3288c2ecf20Sopenharmony_ci (level == 1 && bank->irq_type[d->hwirq] == IRQ_TYPE_LEVEL_HIGH)) 3298c2ecf20Sopenharmony_ci irq_chip_retrigger_hierarchy(d); 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic void stm32_gpio_irq_eoi(struct irq_data *d) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci irq_chip_eoi_parent(d); 3358c2ecf20Sopenharmony_ci stm32_gpio_irq_trigger(d); 3368c2ecf20Sopenharmony_ci}; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int stm32_gpio_set_type(struct irq_data *d, unsigned int type) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank = d->domain->host_data; 3418c2ecf20Sopenharmony_ci u32 parent_type; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci switch (type) { 3448c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: 3458c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: 3468c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_BOTH: 3478c2ecf20Sopenharmony_ci parent_type = type; 3488c2ecf20Sopenharmony_ci break; 3498c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_HIGH: 3508c2ecf20Sopenharmony_ci parent_type = IRQ_TYPE_EDGE_RISING; 3518c2ecf20Sopenharmony_ci break; 3528c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_LOW: 3538c2ecf20Sopenharmony_ci parent_type = IRQ_TYPE_EDGE_FALLING; 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci default: 3568c2ecf20Sopenharmony_ci return -EINVAL; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci bank->irq_type[d->hwirq] = type; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci return irq_chip_set_type_parent(d, parent_type); 3628c2ecf20Sopenharmony_ci}; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic int stm32_gpio_irq_request_resources(struct irq_data *irq_data) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank = irq_data->domain->host_data; 3678c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); 3688c2ecf20Sopenharmony_ci unsigned long flags; 3698c2ecf20Sopenharmony_ci int ret; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci ret = stm32_gpio_direction_input(&bank->gpio_chip, irq_data->hwirq); 3728c2ecf20Sopenharmony_ci if (ret) 3738c2ecf20Sopenharmony_ci return ret; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci ret = gpiochip_lock_as_irq(&bank->gpio_chip, irq_data->hwirq); 3768c2ecf20Sopenharmony_ci if (ret) { 3778c2ecf20Sopenharmony_ci dev_err(pctl->dev, "unable to lock HW IRQ %lu for IRQ\n", 3788c2ecf20Sopenharmony_ci irq_data->hwirq); 3798c2ecf20Sopenharmony_ci return ret; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci flags = irqd_get_trigger_type(irq_data); 3838c2ecf20Sopenharmony_ci if (flags & IRQ_TYPE_LEVEL_MASK) 3848c2ecf20Sopenharmony_ci clk_enable(bank->clk); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci return 0; 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic void stm32_gpio_irq_release_resources(struct irq_data *irq_data) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank = irq_data->domain->host_data; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (bank->irq_type[irq_data->hwirq] & IRQ_TYPE_LEVEL_MASK) 3948c2ecf20Sopenharmony_ci clk_disable(bank->clk); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci gpiochip_unlock_as_irq(&bank->gpio_chip, irq_data->hwirq); 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic void stm32_gpio_irq_unmask(struct irq_data *d) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci irq_chip_unmask_parent(d); 4028c2ecf20Sopenharmony_ci stm32_gpio_irq_trigger(d); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic struct irq_chip stm32_gpio_irq_chip = { 4068c2ecf20Sopenharmony_ci .name = "stm32gpio", 4078c2ecf20Sopenharmony_ci .irq_eoi = stm32_gpio_irq_eoi, 4088c2ecf20Sopenharmony_ci .irq_ack = irq_chip_ack_parent, 4098c2ecf20Sopenharmony_ci .irq_mask = irq_chip_mask_parent, 4108c2ecf20Sopenharmony_ci .irq_unmask = stm32_gpio_irq_unmask, 4118c2ecf20Sopenharmony_ci .irq_set_type = stm32_gpio_set_type, 4128c2ecf20Sopenharmony_ci .irq_set_wake = irq_chip_set_wake_parent, 4138c2ecf20Sopenharmony_ci .irq_request_resources = stm32_gpio_irq_request_resources, 4148c2ecf20Sopenharmony_ci .irq_release_resources = stm32_gpio_irq_release_resources, 4158c2ecf20Sopenharmony_ci}; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic int stm32_gpio_domain_translate(struct irq_domain *d, 4188c2ecf20Sopenharmony_ci struct irq_fwspec *fwspec, 4198c2ecf20Sopenharmony_ci unsigned long *hwirq, 4208c2ecf20Sopenharmony_ci unsigned int *type) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci if ((fwspec->param_count != 2) || 4238c2ecf20Sopenharmony_ci (fwspec->param[0] >= STM32_GPIO_IRQ_LINE)) 4248c2ecf20Sopenharmony_ci return -EINVAL; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci *hwirq = fwspec->param[0]; 4278c2ecf20Sopenharmony_ci *type = fwspec->param[1]; 4288c2ecf20Sopenharmony_ci return 0; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic int stm32_gpio_domain_activate(struct irq_domain *d, 4328c2ecf20Sopenharmony_ci struct irq_data *irq_data, bool reserve) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank = d->host_data; 4358c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); 4368c2ecf20Sopenharmony_ci unsigned long flags; 4378c2ecf20Sopenharmony_ci int ret = 0; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci /* 4408c2ecf20Sopenharmony_ci * gpio irq mux is shared between several banks, a lock has to be done 4418c2ecf20Sopenharmony_ci * to avoid overriding. 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_ci spin_lock_irqsave(&pctl->irqmux_lock, flags); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (pctl->hwlock) { 4468c2ecf20Sopenharmony_ci ret = hwspin_lock_timeout_in_atomic(pctl->hwlock, 4478c2ecf20Sopenharmony_ci HWSPNLCK_TIMEOUT); 4488c2ecf20Sopenharmony_ci if (ret) { 4498c2ecf20Sopenharmony_ci dev_err(pctl->dev, "Can't get hwspinlock\n"); 4508c2ecf20Sopenharmony_ci goto unlock; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (pctl->irqmux_map & BIT(irq_data->hwirq)) { 4558c2ecf20Sopenharmony_ci dev_err(pctl->dev, "irq line %ld already requested.\n", 4568c2ecf20Sopenharmony_ci irq_data->hwirq); 4578c2ecf20Sopenharmony_ci ret = -EBUSY; 4588c2ecf20Sopenharmony_ci if (pctl->hwlock) 4598c2ecf20Sopenharmony_ci hwspin_unlock_in_atomic(pctl->hwlock); 4608c2ecf20Sopenharmony_ci goto unlock; 4618c2ecf20Sopenharmony_ci } else { 4628c2ecf20Sopenharmony_ci pctl->irqmux_map |= BIT(irq_data->hwirq); 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->bank_ioport_nr); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci if (pctl->hwlock) 4688c2ecf20Sopenharmony_ci hwspin_unlock_in_atomic(pctl->hwlock); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ciunlock: 4718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pctl->irqmux_lock, flags); 4728c2ecf20Sopenharmony_ci return ret; 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic void stm32_gpio_domain_deactivate(struct irq_domain *d, 4768c2ecf20Sopenharmony_ci struct irq_data *irq_data) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank = d->host_data; 4798c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); 4808c2ecf20Sopenharmony_ci unsigned long flags; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci spin_lock_irqsave(&pctl->irqmux_lock, flags); 4838c2ecf20Sopenharmony_ci pctl->irqmux_map &= ~BIT(irq_data->hwirq); 4848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pctl->irqmux_lock, flags); 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic int stm32_gpio_domain_alloc(struct irq_domain *d, 4888c2ecf20Sopenharmony_ci unsigned int virq, 4898c2ecf20Sopenharmony_ci unsigned int nr_irqs, void *data) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank = d->host_data; 4928c2ecf20Sopenharmony_ci struct irq_fwspec *fwspec = data; 4938c2ecf20Sopenharmony_ci struct irq_fwspec parent_fwspec; 4948c2ecf20Sopenharmony_ci irq_hw_number_t hwirq; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci hwirq = fwspec->param[0]; 4978c2ecf20Sopenharmony_ci parent_fwspec.fwnode = d->parent->fwnode; 4988c2ecf20Sopenharmony_ci parent_fwspec.param_count = 2; 4998c2ecf20Sopenharmony_ci parent_fwspec.param[0] = fwspec->param[0]; 5008c2ecf20Sopenharmony_ci parent_fwspec.param[1] = fwspec->param[1]; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci irq_domain_set_hwirq_and_chip(d, virq, hwirq, &stm32_gpio_irq_chip, 5038c2ecf20Sopenharmony_ci bank); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci return irq_domain_alloc_irqs_parent(d, virq, nr_irqs, &parent_fwspec); 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic const struct irq_domain_ops stm32_gpio_domain_ops = { 5098c2ecf20Sopenharmony_ci .translate = stm32_gpio_domain_translate, 5108c2ecf20Sopenharmony_ci .alloc = stm32_gpio_domain_alloc, 5118c2ecf20Sopenharmony_ci .free = irq_domain_free_irqs_common, 5128c2ecf20Sopenharmony_ci .activate = stm32_gpio_domain_activate, 5138c2ecf20Sopenharmony_ci .deactivate = stm32_gpio_domain_deactivate, 5148c2ecf20Sopenharmony_ci}; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci/* Pinctrl functions */ 5178c2ecf20Sopenharmony_cistatic struct stm32_pinctrl_group * 5188c2ecf20Sopenharmony_cistm32_pctrl_find_group_by_pin(struct stm32_pinctrl *pctl, u32 pin) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci int i; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci for (i = 0; i < pctl->ngroups; i++) { 5238c2ecf20Sopenharmony_ci struct stm32_pinctrl_group *grp = pctl->groups + i; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (grp->pin == pin) 5268c2ecf20Sopenharmony_ci return grp; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci return NULL; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic bool stm32_pctrl_is_function_valid(struct stm32_pinctrl *pctl, 5338c2ecf20Sopenharmony_ci u32 pin_num, u32 fnum) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci int i; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci for (i = 0; i < pctl->npins; i++) { 5388c2ecf20Sopenharmony_ci const struct stm32_desc_pin *pin = pctl->pins + i; 5398c2ecf20Sopenharmony_ci const struct stm32_desc_function *func = pin->functions; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (pin->pin.number != pin_num) 5428c2ecf20Sopenharmony_ci continue; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci while (func && func->name) { 5458c2ecf20Sopenharmony_ci if (func->num == fnum) 5468c2ecf20Sopenharmony_ci return true; 5478c2ecf20Sopenharmony_ci func++; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci break; 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci return false; 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic int stm32_pctrl_dt_node_to_map_func(struct stm32_pinctrl *pctl, 5578c2ecf20Sopenharmony_ci u32 pin, u32 fnum, struct stm32_pinctrl_group *grp, 5588c2ecf20Sopenharmony_ci struct pinctrl_map **map, unsigned *reserved_maps, 5598c2ecf20Sopenharmony_ci unsigned *num_maps) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci if (*num_maps == *reserved_maps) 5628c2ecf20Sopenharmony_ci return -ENOSPC; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; 5658c2ecf20Sopenharmony_ci (*map)[*num_maps].data.mux.group = grp->name; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (!stm32_pctrl_is_function_valid(pctl, pin, fnum)) { 5688c2ecf20Sopenharmony_ci dev_err(pctl->dev, "invalid function %d on pin %d .\n", 5698c2ecf20Sopenharmony_ci fnum, pin); 5708c2ecf20Sopenharmony_ci return -EINVAL; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci (*map)[*num_maps].data.mux.function = stm32_gpio_functions[fnum]; 5748c2ecf20Sopenharmony_ci (*num_maps)++; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci return 0; 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic int stm32_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, 5808c2ecf20Sopenharmony_ci struct device_node *node, 5818c2ecf20Sopenharmony_ci struct pinctrl_map **map, 5828c2ecf20Sopenharmony_ci unsigned *reserved_maps, 5838c2ecf20Sopenharmony_ci unsigned *num_maps) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl; 5868c2ecf20Sopenharmony_ci struct stm32_pinctrl_group *grp; 5878c2ecf20Sopenharmony_ci struct property *pins; 5888c2ecf20Sopenharmony_ci u32 pinfunc, pin, func; 5898c2ecf20Sopenharmony_ci unsigned long *configs; 5908c2ecf20Sopenharmony_ci unsigned int num_configs; 5918c2ecf20Sopenharmony_ci bool has_config = 0; 5928c2ecf20Sopenharmony_ci unsigned reserve = 0; 5938c2ecf20Sopenharmony_ci int num_pins, num_funcs, maps_per_pin, i, err = 0; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci pctl = pinctrl_dev_get_drvdata(pctldev); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci pins = of_find_property(node, "pinmux", NULL); 5988c2ecf20Sopenharmony_ci if (!pins) { 5998c2ecf20Sopenharmony_ci dev_err(pctl->dev, "missing pins property in node %pOFn .\n", 6008c2ecf20Sopenharmony_ci node); 6018c2ecf20Sopenharmony_ci return -EINVAL; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci err = pinconf_generic_parse_dt_config(node, pctldev, &configs, 6058c2ecf20Sopenharmony_ci &num_configs); 6068c2ecf20Sopenharmony_ci if (err) 6078c2ecf20Sopenharmony_ci return err; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (num_configs) 6108c2ecf20Sopenharmony_ci has_config = 1; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci num_pins = pins->length / sizeof(u32); 6138c2ecf20Sopenharmony_ci num_funcs = num_pins; 6148c2ecf20Sopenharmony_ci maps_per_pin = 0; 6158c2ecf20Sopenharmony_ci if (num_funcs) 6168c2ecf20Sopenharmony_ci maps_per_pin++; 6178c2ecf20Sopenharmony_ci if (has_config && num_pins >= 1) 6188c2ecf20Sopenharmony_ci maps_per_pin++; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci if (!num_pins || !maps_per_pin) { 6218c2ecf20Sopenharmony_ci err = -EINVAL; 6228c2ecf20Sopenharmony_ci goto exit; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci reserve = num_pins * maps_per_pin; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci err = pinctrl_utils_reserve_map(pctldev, map, 6288c2ecf20Sopenharmony_ci reserved_maps, num_maps, reserve); 6298c2ecf20Sopenharmony_ci if (err) 6308c2ecf20Sopenharmony_ci goto exit; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci for (i = 0; i < num_pins; i++) { 6338c2ecf20Sopenharmony_ci err = of_property_read_u32_index(node, "pinmux", 6348c2ecf20Sopenharmony_ci i, &pinfunc); 6358c2ecf20Sopenharmony_ci if (err) 6368c2ecf20Sopenharmony_ci goto exit; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci pin = STM32_GET_PIN_NO(pinfunc); 6398c2ecf20Sopenharmony_ci func = STM32_GET_PIN_FUNC(pinfunc); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (!stm32_pctrl_is_function_valid(pctl, pin, func)) { 6428c2ecf20Sopenharmony_ci dev_err(pctl->dev, "invalid function.\n"); 6438c2ecf20Sopenharmony_ci err = -EINVAL; 6448c2ecf20Sopenharmony_ci goto exit; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci grp = stm32_pctrl_find_group_by_pin(pctl, pin); 6488c2ecf20Sopenharmony_ci if (!grp) { 6498c2ecf20Sopenharmony_ci dev_err(pctl->dev, "unable to match pin %d to group\n", 6508c2ecf20Sopenharmony_ci pin); 6518c2ecf20Sopenharmony_ci err = -EINVAL; 6528c2ecf20Sopenharmony_ci goto exit; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci err = stm32_pctrl_dt_node_to_map_func(pctl, pin, func, grp, map, 6568c2ecf20Sopenharmony_ci reserved_maps, num_maps); 6578c2ecf20Sopenharmony_ci if (err) 6588c2ecf20Sopenharmony_ci goto exit; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci if (has_config) { 6618c2ecf20Sopenharmony_ci err = pinctrl_utils_add_map_configs(pctldev, map, 6628c2ecf20Sopenharmony_ci reserved_maps, num_maps, grp->name, 6638c2ecf20Sopenharmony_ci configs, num_configs, 6648c2ecf20Sopenharmony_ci PIN_MAP_TYPE_CONFIGS_GROUP); 6658c2ecf20Sopenharmony_ci if (err) 6668c2ecf20Sopenharmony_ci goto exit; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ciexit: 6718c2ecf20Sopenharmony_ci kfree(configs); 6728c2ecf20Sopenharmony_ci return err; 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic int stm32_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, 6768c2ecf20Sopenharmony_ci struct device_node *np_config, 6778c2ecf20Sopenharmony_ci struct pinctrl_map **map, unsigned *num_maps) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci struct device_node *np; 6808c2ecf20Sopenharmony_ci unsigned reserved_maps; 6818c2ecf20Sopenharmony_ci int ret; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci *map = NULL; 6848c2ecf20Sopenharmony_ci *num_maps = 0; 6858c2ecf20Sopenharmony_ci reserved_maps = 0; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci for_each_child_of_node(np_config, np) { 6888c2ecf20Sopenharmony_ci ret = stm32_pctrl_dt_subnode_to_map(pctldev, np, map, 6898c2ecf20Sopenharmony_ci &reserved_maps, num_maps); 6908c2ecf20Sopenharmony_ci if (ret < 0) { 6918c2ecf20Sopenharmony_ci pinctrl_utils_free_map(pctldev, *map, *num_maps); 6928c2ecf20Sopenharmony_ci of_node_put(np); 6938c2ecf20Sopenharmony_ci return ret; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci return 0; 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cistatic int stm32_pctrl_get_groups_count(struct pinctrl_dev *pctldev) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci return pctl->ngroups; 7058c2ecf20Sopenharmony_ci} 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_cistatic const char *stm32_pctrl_get_group_name(struct pinctrl_dev *pctldev, 7088c2ecf20Sopenharmony_ci unsigned group) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci return pctl->groups[group].name; 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cistatic int stm32_pctrl_get_group_pins(struct pinctrl_dev *pctldev, 7168c2ecf20Sopenharmony_ci unsigned group, 7178c2ecf20Sopenharmony_ci const unsigned **pins, 7188c2ecf20Sopenharmony_ci unsigned *num_pins) 7198c2ecf20Sopenharmony_ci{ 7208c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci *pins = (unsigned *)&pctl->groups[group].pin; 7238c2ecf20Sopenharmony_ci *num_pins = 1; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci return 0; 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_cistatic const struct pinctrl_ops stm32_pctrl_ops = { 7298c2ecf20Sopenharmony_ci .dt_node_to_map = stm32_pctrl_dt_node_to_map, 7308c2ecf20Sopenharmony_ci .dt_free_map = pinctrl_utils_free_map, 7318c2ecf20Sopenharmony_ci .get_groups_count = stm32_pctrl_get_groups_count, 7328c2ecf20Sopenharmony_ci .get_group_name = stm32_pctrl_get_group_name, 7338c2ecf20Sopenharmony_ci .get_group_pins = stm32_pctrl_get_group_pins, 7348c2ecf20Sopenharmony_ci}; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci/* Pinmux functions */ 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic int stm32_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) 7408c2ecf20Sopenharmony_ci{ 7418c2ecf20Sopenharmony_ci return ARRAY_SIZE(stm32_gpio_functions); 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic const char *stm32_pmx_get_func_name(struct pinctrl_dev *pctldev, 7458c2ecf20Sopenharmony_ci unsigned selector) 7468c2ecf20Sopenharmony_ci{ 7478c2ecf20Sopenharmony_ci return stm32_gpio_functions[selector]; 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_cistatic int stm32_pmx_get_func_groups(struct pinctrl_dev *pctldev, 7518c2ecf20Sopenharmony_ci unsigned function, 7528c2ecf20Sopenharmony_ci const char * const **groups, 7538c2ecf20Sopenharmony_ci unsigned * const num_groups) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci *groups = pctl->grp_names; 7588c2ecf20Sopenharmony_ci *num_groups = pctl->ngroups; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci return 0; 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_cistatic int stm32_pmx_set_mode(struct stm32_gpio_bank *bank, 7648c2ecf20Sopenharmony_ci int pin, u32 mode, u32 alt) 7658c2ecf20Sopenharmony_ci{ 7668c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); 7678c2ecf20Sopenharmony_ci u32 val; 7688c2ecf20Sopenharmony_ci int alt_shift = (pin % 8) * 4; 7698c2ecf20Sopenharmony_ci int alt_offset = STM32_GPIO_AFRL + (pin / 8) * 4; 7708c2ecf20Sopenharmony_ci unsigned long flags; 7718c2ecf20Sopenharmony_ci int err = 0; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci clk_enable(bank->clk); 7748c2ecf20Sopenharmony_ci spin_lock_irqsave(&bank->lock, flags); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (pctl->hwlock) { 7778c2ecf20Sopenharmony_ci err = hwspin_lock_timeout_in_atomic(pctl->hwlock, 7788c2ecf20Sopenharmony_ci HWSPNLCK_TIMEOUT); 7798c2ecf20Sopenharmony_ci if (err) { 7808c2ecf20Sopenharmony_ci dev_err(pctl->dev, "Can't get hwspinlock\n"); 7818c2ecf20Sopenharmony_ci goto unlock; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci val = readl_relaxed(bank->base + alt_offset); 7868c2ecf20Sopenharmony_ci val &= ~GENMASK(alt_shift + 3, alt_shift); 7878c2ecf20Sopenharmony_ci val |= (alt << alt_shift); 7888c2ecf20Sopenharmony_ci writel_relaxed(val, bank->base + alt_offset); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci val = readl_relaxed(bank->base + STM32_GPIO_MODER); 7918c2ecf20Sopenharmony_ci val &= ~GENMASK(pin * 2 + 1, pin * 2); 7928c2ecf20Sopenharmony_ci val |= mode << (pin * 2); 7938c2ecf20Sopenharmony_ci writel_relaxed(val, bank->base + STM32_GPIO_MODER); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci if (pctl->hwlock) 7968c2ecf20Sopenharmony_ci hwspin_unlock_in_atomic(pctl->hwlock); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci stm32_gpio_backup_mode(bank, pin, mode, alt); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ciunlock: 8018c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bank->lock, flags); 8028c2ecf20Sopenharmony_ci clk_disable(bank->clk); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci return err; 8058c2ecf20Sopenharmony_ci} 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_civoid stm32_pmx_get_mode(struct stm32_gpio_bank *bank, int pin, u32 *mode, 8088c2ecf20Sopenharmony_ci u32 *alt) 8098c2ecf20Sopenharmony_ci{ 8108c2ecf20Sopenharmony_ci u32 val; 8118c2ecf20Sopenharmony_ci int alt_shift = (pin % 8) * 4; 8128c2ecf20Sopenharmony_ci int alt_offset = STM32_GPIO_AFRL + (pin / 8) * 4; 8138c2ecf20Sopenharmony_ci unsigned long flags; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci clk_enable(bank->clk); 8168c2ecf20Sopenharmony_ci spin_lock_irqsave(&bank->lock, flags); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci val = readl_relaxed(bank->base + alt_offset); 8198c2ecf20Sopenharmony_ci val &= GENMASK(alt_shift + 3, alt_shift); 8208c2ecf20Sopenharmony_ci *alt = val >> alt_shift; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci val = readl_relaxed(bank->base + STM32_GPIO_MODER); 8238c2ecf20Sopenharmony_ci val &= GENMASK(pin * 2 + 1, pin * 2); 8248c2ecf20Sopenharmony_ci *mode = val >> (pin * 2); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bank->lock, flags); 8278c2ecf20Sopenharmony_ci clk_disable(bank->clk); 8288c2ecf20Sopenharmony_ci} 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_cistatic int stm32_pmx_set_mux(struct pinctrl_dev *pctldev, 8318c2ecf20Sopenharmony_ci unsigned function, 8328c2ecf20Sopenharmony_ci unsigned group) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci bool ret; 8358c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 8368c2ecf20Sopenharmony_ci struct stm32_pinctrl_group *g = pctl->groups + group; 8378c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range; 8388c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank; 8398c2ecf20Sopenharmony_ci u32 mode, alt; 8408c2ecf20Sopenharmony_ci int pin; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci ret = stm32_pctrl_is_function_valid(pctl, g->pin, function); 8438c2ecf20Sopenharmony_ci if (!ret) { 8448c2ecf20Sopenharmony_ci dev_err(pctl->dev, "invalid function %d on group %d .\n", 8458c2ecf20Sopenharmony_ci function, group); 8468c2ecf20Sopenharmony_ci return -EINVAL; 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci range = pinctrl_find_gpio_range_from_pin(pctldev, g->pin); 8508c2ecf20Sopenharmony_ci if (!range) { 8518c2ecf20Sopenharmony_ci dev_err(pctl->dev, "No gpio range defined.\n"); 8528c2ecf20Sopenharmony_ci return -EINVAL; 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci bank = gpiochip_get_data(range->gc); 8568c2ecf20Sopenharmony_ci pin = stm32_gpio_pin(g->pin); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci mode = stm32_gpio_get_mode(function); 8598c2ecf20Sopenharmony_ci alt = stm32_gpio_get_alt(function); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci return stm32_pmx_set_mode(bank, pin, mode, alt); 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic int stm32_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, 8658c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range, unsigned gpio, 8668c2ecf20Sopenharmony_ci bool input) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank = gpiochip_get_data(range->gc); 8698c2ecf20Sopenharmony_ci int pin = stm32_gpio_pin(gpio); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci return stm32_pmx_set_mode(bank, pin, !input, 0); 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_cistatic const struct pinmux_ops stm32_pmx_ops = { 8758c2ecf20Sopenharmony_ci .get_functions_count = stm32_pmx_get_funcs_cnt, 8768c2ecf20Sopenharmony_ci .get_function_name = stm32_pmx_get_func_name, 8778c2ecf20Sopenharmony_ci .get_function_groups = stm32_pmx_get_func_groups, 8788c2ecf20Sopenharmony_ci .set_mux = stm32_pmx_set_mux, 8798c2ecf20Sopenharmony_ci .gpio_set_direction = stm32_pmx_gpio_set_direction, 8808c2ecf20Sopenharmony_ci .strict = true, 8818c2ecf20Sopenharmony_ci}; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci/* Pinconf functions */ 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_cistatic int stm32_pconf_set_driving(struct stm32_gpio_bank *bank, 8868c2ecf20Sopenharmony_ci unsigned offset, u32 drive) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); 8898c2ecf20Sopenharmony_ci unsigned long flags; 8908c2ecf20Sopenharmony_ci u32 val; 8918c2ecf20Sopenharmony_ci int err = 0; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci clk_enable(bank->clk); 8948c2ecf20Sopenharmony_ci spin_lock_irqsave(&bank->lock, flags); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci if (pctl->hwlock) { 8978c2ecf20Sopenharmony_ci err = hwspin_lock_timeout_in_atomic(pctl->hwlock, 8988c2ecf20Sopenharmony_ci HWSPNLCK_TIMEOUT); 8998c2ecf20Sopenharmony_ci if (err) { 9008c2ecf20Sopenharmony_ci dev_err(pctl->dev, "Can't get hwspinlock\n"); 9018c2ecf20Sopenharmony_ci goto unlock; 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci val = readl_relaxed(bank->base + STM32_GPIO_TYPER); 9068c2ecf20Sopenharmony_ci val &= ~BIT(offset); 9078c2ecf20Sopenharmony_ci val |= drive << offset; 9088c2ecf20Sopenharmony_ci writel_relaxed(val, bank->base + STM32_GPIO_TYPER); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci if (pctl->hwlock) 9118c2ecf20Sopenharmony_ci hwspin_unlock_in_atomic(pctl->hwlock); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci stm32_gpio_backup_driving(bank, offset, drive); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ciunlock: 9168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bank->lock, flags); 9178c2ecf20Sopenharmony_ci clk_disable(bank->clk); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci return err; 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cistatic u32 stm32_pconf_get_driving(struct stm32_gpio_bank *bank, 9238c2ecf20Sopenharmony_ci unsigned int offset) 9248c2ecf20Sopenharmony_ci{ 9258c2ecf20Sopenharmony_ci unsigned long flags; 9268c2ecf20Sopenharmony_ci u32 val; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci clk_enable(bank->clk); 9298c2ecf20Sopenharmony_ci spin_lock_irqsave(&bank->lock, flags); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci val = readl_relaxed(bank->base + STM32_GPIO_TYPER); 9328c2ecf20Sopenharmony_ci val &= BIT(offset); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bank->lock, flags); 9358c2ecf20Sopenharmony_ci clk_disable(bank->clk); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci return (val >> offset); 9388c2ecf20Sopenharmony_ci} 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_cistatic int stm32_pconf_set_speed(struct stm32_gpio_bank *bank, 9418c2ecf20Sopenharmony_ci unsigned offset, u32 speed) 9428c2ecf20Sopenharmony_ci{ 9438c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); 9448c2ecf20Sopenharmony_ci unsigned long flags; 9458c2ecf20Sopenharmony_ci u32 val; 9468c2ecf20Sopenharmony_ci int err = 0; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci clk_enable(bank->clk); 9498c2ecf20Sopenharmony_ci spin_lock_irqsave(&bank->lock, flags); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci if (pctl->hwlock) { 9528c2ecf20Sopenharmony_ci err = hwspin_lock_timeout_in_atomic(pctl->hwlock, 9538c2ecf20Sopenharmony_ci HWSPNLCK_TIMEOUT); 9548c2ecf20Sopenharmony_ci if (err) { 9558c2ecf20Sopenharmony_ci dev_err(pctl->dev, "Can't get hwspinlock\n"); 9568c2ecf20Sopenharmony_ci goto unlock; 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci val = readl_relaxed(bank->base + STM32_GPIO_SPEEDR); 9618c2ecf20Sopenharmony_ci val &= ~GENMASK(offset * 2 + 1, offset * 2); 9628c2ecf20Sopenharmony_ci val |= speed << (offset * 2); 9638c2ecf20Sopenharmony_ci writel_relaxed(val, bank->base + STM32_GPIO_SPEEDR); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci if (pctl->hwlock) 9668c2ecf20Sopenharmony_ci hwspin_unlock_in_atomic(pctl->hwlock); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci stm32_gpio_backup_speed(bank, offset, speed); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ciunlock: 9718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bank->lock, flags); 9728c2ecf20Sopenharmony_ci clk_disable(bank->clk); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci return err; 9758c2ecf20Sopenharmony_ci} 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_cistatic u32 stm32_pconf_get_speed(struct stm32_gpio_bank *bank, 9788c2ecf20Sopenharmony_ci unsigned int offset) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci unsigned long flags; 9818c2ecf20Sopenharmony_ci u32 val; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci clk_enable(bank->clk); 9848c2ecf20Sopenharmony_ci spin_lock_irqsave(&bank->lock, flags); 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci val = readl_relaxed(bank->base + STM32_GPIO_SPEEDR); 9878c2ecf20Sopenharmony_ci val &= GENMASK(offset * 2 + 1, offset * 2); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bank->lock, flags); 9908c2ecf20Sopenharmony_ci clk_disable(bank->clk); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci return (val >> (offset * 2)); 9938c2ecf20Sopenharmony_ci} 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_cistatic int stm32_pconf_set_bias(struct stm32_gpio_bank *bank, 9968c2ecf20Sopenharmony_ci unsigned offset, u32 bias) 9978c2ecf20Sopenharmony_ci{ 9988c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); 9998c2ecf20Sopenharmony_ci unsigned long flags; 10008c2ecf20Sopenharmony_ci u32 val; 10018c2ecf20Sopenharmony_ci int err = 0; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci clk_enable(bank->clk); 10048c2ecf20Sopenharmony_ci spin_lock_irqsave(&bank->lock, flags); 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci if (pctl->hwlock) { 10078c2ecf20Sopenharmony_ci err = hwspin_lock_timeout_in_atomic(pctl->hwlock, 10088c2ecf20Sopenharmony_ci HWSPNLCK_TIMEOUT); 10098c2ecf20Sopenharmony_ci if (err) { 10108c2ecf20Sopenharmony_ci dev_err(pctl->dev, "Can't get hwspinlock\n"); 10118c2ecf20Sopenharmony_ci goto unlock; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci val = readl_relaxed(bank->base + STM32_GPIO_PUPDR); 10168c2ecf20Sopenharmony_ci val &= ~GENMASK(offset * 2 + 1, offset * 2); 10178c2ecf20Sopenharmony_ci val |= bias << (offset * 2); 10188c2ecf20Sopenharmony_ci writel_relaxed(val, bank->base + STM32_GPIO_PUPDR); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci if (pctl->hwlock) 10218c2ecf20Sopenharmony_ci hwspin_unlock_in_atomic(pctl->hwlock); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci stm32_gpio_backup_bias(bank, offset, bias); 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ciunlock: 10268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bank->lock, flags); 10278c2ecf20Sopenharmony_ci clk_disable(bank->clk); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci return err; 10308c2ecf20Sopenharmony_ci} 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_cistatic u32 stm32_pconf_get_bias(struct stm32_gpio_bank *bank, 10338c2ecf20Sopenharmony_ci unsigned int offset) 10348c2ecf20Sopenharmony_ci{ 10358c2ecf20Sopenharmony_ci unsigned long flags; 10368c2ecf20Sopenharmony_ci u32 val; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci clk_enable(bank->clk); 10398c2ecf20Sopenharmony_ci spin_lock_irqsave(&bank->lock, flags); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci val = readl_relaxed(bank->base + STM32_GPIO_PUPDR); 10428c2ecf20Sopenharmony_ci val &= GENMASK(offset * 2 + 1, offset * 2); 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bank->lock, flags); 10458c2ecf20Sopenharmony_ci clk_disable(bank->clk); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci return (val >> (offset * 2)); 10488c2ecf20Sopenharmony_ci} 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_cistatic bool stm32_pconf_get(struct stm32_gpio_bank *bank, 10518c2ecf20Sopenharmony_ci unsigned int offset, bool dir) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci unsigned long flags; 10548c2ecf20Sopenharmony_ci u32 val; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci clk_enable(bank->clk); 10578c2ecf20Sopenharmony_ci spin_lock_irqsave(&bank->lock, flags); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci if (dir) 10608c2ecf20Sopenharmony_ci val = !!(readl_relaxed(bank->base + STM32_GPIO_IDR) & 10618c2ecf20Sopenharmony_ci BIT(offset)); 10628c2ecf20Sopenharmony_ci else 10638c2ecf20Sopenharmony_ci val = !!(readl_relaxed(bank->base + STM32_GPIO_ODR) & 10648c2ecf20Sopenharmony_ci BIT(offset)); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bank->lock, flags); 10678c2ecf20Sopenharmony_ci clk_disable(bank->clk); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci return val; 10708c2ecf20Sopenharmony_ci} 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_cistatic int stm32_pconf_parse_conf(struct pinctrl_dev *pctldev, 10738c2ecf20Sopenharmony_ci unsigned int pin, enum pin_config_param param, 10748c2ecf20Sopenharmony_ci enum pin_config_param arg) 10758c2ecf20Sopenharmony_ci{ 10768c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 10778c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range; 10788c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank; 10798c2ecf20Sopenharmony_ci int offset, ret = 0; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, pin); 10828c2ecf20Sopenharmony_ci if (!range) { 10838c2ecf20Sopenharmony_ci dev_err(pctl->dev, "No gpio range defined.\n"); 10848c2ecf20Sopenharmony_ci return -EINVAL; 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci bank = gpiochip_get_data(range->gc); 10888c2ecf20Sopenharmony_ci offset = stm32_gpio_pin(pin); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci switch (param) { 10918c2ecf20Sopenharmony_ci case PIN_CONFIG_DRIVE_PUSH_PULL: 10928c2ecf20Sopenharmony_ci ret = stm32_pconf_set_driving(bank, offset, 0); 10938c2ecf20Sopenharmony_ci break; 10948c2ecf20Sopenharmony_ci case PIN_CONFIG_DRIVE_OPEN_DRAIN: 10958c2ecf20Sopenharmony_ci ret = stm32_pconf_set_driving(bank, offset, 1); 10968c2ecf20Sopenharmony_ci break; 10978c2ecf20Sopenharmony_ci case PIN_CONFIG_SLEW_RATE: 10988c2ecf20Sopenharmony_ci ret = stm32_pconf_set_speed(bank, offset, arg); 10998c2ecf20Sopenharmony_ci break; 11008c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 11018c2ecf20Sopenharmony_ci ret = stm32_pconf_set_bias(bank, offset, 0); 11028c2ecf20Sopenharmony_ci break; 11038c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 11048c2ecf20Sopenharmony_ci ret = stm32_pconf_set_bias(bank, offset, 1); 11058c2ecf20Sopenharmony_ci break; 11068c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 11078c2ecf20Sopenharmony_ci ret = stm32_pconf_set_bias(bank, offset, 2); 11088c2ecf20Sopenharmony_ci break; 11098c2ecf20Sopenharmony_ci case PIN_CONFIG_OUTPUT: 11108c2ecf20Sopenharmony_ci __stm32_gpio_set(bank, offset, arg); 11118c2ecf20Sopenharmony_ci ret = stm32_pmx_gpio_set_direction(pctldev, range, pin, false); 11128c2ecf20Sopenharmony_ci break; 11138c2ecf20Sopenharmony_ci default: 11148c2ecf20Sopenharmony_ci ret = -ENOTSUPP; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci return ret; 11188c2ecf20Sopenharmony_ci} 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_cistatic int stm32_pconf_group_get(struct pinctrl_dev *pctldev, 11218c2ecf20Sopenharmony_ci unsigned group, 11228c2ecf20Sopenharmony_ci unsigned long *config) 11238c2ecf20Sopenharmony_ci{ 11248c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci *config = pctl->groups[group].config; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci return 0; 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_cistatic int stm32_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, 11328c2ecf20Sopenharmony_ci unsigned long *configs, unsigned num_configs) 11338c2ecf20Sopenharmony_ci{ 11348c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 11358c2ecf20Sopenharmony_ci struct stm32_pinctrl_group *g = &pctl->groups[group]; 11368c2ecf20Sopenharmony_ci int i, ret; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci for (i = 0; i < num_configs; i++) { 11398c2ecf20Sopenharmony_ci mutex_lock(&pctldev->mutex); 11408c2ecf20Sopenharmony_ci ret = stm32_pconf_parse_conf(pctldev, g->pin, 11418c2ecf20Sopenharmony_ci pinconf_to_config_param(configs[i]), 11428c2ecf20Sopenharmony_ci pinconf_to_config_argument(configs[i])); 11438c2ecf20Sopenharmony_ci mutex_unlock(&pctldev->mutex); 11448c2ecf20Sopenharmony_ci if (ret < 0) 11458c2ecf20Sopenharmony_ci return ret; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci g->config = configs[i]; 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci return 0; 11518c2ecf20Sopenharmony_ci} 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_cistatic int stm32_pconf_set(struct pinctrl_dev *pctldev, unsigned int pin, 11548c2ecf20Sopenharmony_ci unsigned long *configs, unsigned int num_configs) 11558c2ecf20Sopenharmony_ci{ 11568c2ecf20Sopenharmony_ci int i, ret; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci for (i = 0; i < num_configs; i++) { 11598c2ecf20Sopenharmony_ci ret = stm32_pconf_parse_conf(pctldev, pin, 11608c2ecf20Sopenharmony_ci pinconf_to_config_param(configs[i]), 11618c2ecf20Sopenharmony_ci pinconf_to_config_argument(configs[i])); 11628c2ecf20Sopenharmony_ci if (ret < 0) 11638c2ecf20Sopenharmony_ci return ret; 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci return 0; 11678c2ecf20Sopenharmony_ci} 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_cistatic void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, 11708c2ecf20Sopenharmony_ci struct seq_file *s, 11718c2ecf20Sopenharmony_ci unsigned int pin) 11728c2ecf20Sopenharmony_ci{ 11738c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range; 11748c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank; 11758c2ecf20Sopenharmony_ci int offset; 11768c2ecf20Sopenharmony_ci u32 mode, alt, drive, speed, bias; 11778c2ecf20Sopenharmony_ci static const char * const modes[] = { 11788c2ecf20Sopenharmony_ci "input", "output", "alternate", "analog" }; 11798c2ecf20Sopenharmony_ci static const char * const speeds[] = { 11808c2ecf20Sopenharmony_ci "low", "medium", "high", "very high" }; 11818c2ecf20Sopenharmony_ci static const char * const biasing[] = { 11828c2ecf20Sopenharmony_ci "floating", "pull up", "pull down", "" }; 11838c2ecf20Sopenharmony_ci bool val; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, pin); 11868c2ecf20Sopenharmony_ci if (!range) 11878c2ecf20Sopenharmony_ci return; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci bank = gpiochip_get_data(range->gc); 11908c2ecf20Sopenharmony_ci offset = stm32_gpio_pin(pin); 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci stm32_pmx_get_mode(bank, offset, &mode, &alt); 11938c2ecf20Sopenharmony_ci bias = stm32_pconf_get_bias(bank, offset); 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci seq_printf(s, "%s ", modes[mode]); 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci switch (mode) { 11988c2ecf20Sopenharmony_ci /* input */ 11998c2ecf20Sopenharmony_ci case 0: 12008c2ecf20Sopenharmony_ci val = stm32_pconf_get(bank, offset, true); 12018c2ecf20Sopenharmony_ci seq_printf(s, "- %s - %s", 12028c2ecf20Sopenharmony_ci val ? "high" : "low", 12038c2ecf20Sopenharmony_ci biasing[bias]); 12048c2ecf20Sopenharmony_ci break; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci /* output */ 12078c2ecf20Sopenharmony_ci case 1: 12088c2ecf20Sopenharmony_ci drive = stm32_pconf_get_driving(bank, offset); 12098c2ecf20Sopenharmony_ci speed = stm32_pconf_get_speed(bank, offset); 12108c2ecf20Sopenharmony_ci val = stm32_pconf_get(bank, offset, false); 12118c2ecf20Sopenharmony_ci seq_printf(s, "- %s - %s - %s - %s %s", 12128c2ecf20Sopenharmony_ci val ? "high" : "low", 12138c2ecf20Sopenharmony_ci drive ? "open drain" : "push pull", 12148c2ecf20Sopenharmony_ci biasing[bias], 12158c2ecf20Sopenharmony_ci speeds[speed], "speed"); 12168c2ecf20Sopenharmony_ci break; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci /* alternate */ 12198c2ecf20Sopenharmony_ci case 2: 12208c2ecf20Sopenharmony_ci drive = stm32_pconf_get_driving(bank, offset); 12218c2ecf20Sopenharmony_ci speed = stm32_pconf_get_speed(bank, offset); 12228c2ecf20Sopenharmony_ci seq_printf(s, "%d - %s - %s - %s %s", alt, 12238c2ecf20Sopenharmony_ci drive ? "open drain" : "push pull", 12248c2ecf20Sopenharmony_ci biasing[bias], 12258c2ecf20Sopenharmony_ci speeds[speed], "speed"); 12268c2ecf20Sopenharmony_ci break; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci /* analog */ 12298c2ecf20Sopenharmony_ci case 3: 12308c2ecf20Sopenharmony_ci break; 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci} 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_cistatic const struct pinconf_ops stm32_pconf_ops = { 12358c2ecf20Sopenharmony_ci .pin_config_group_get = stm32_pconf_group_get, 12368c2ecf20Sopenharmony_ci .pin_config_group_set = stm32_pconf_group_set, 12378c2ecf20Sopenharmony_ci .pin_config_set = stm32_pconf_set, 12388c2ecf20Sopenharmony_ci .pin_config_dbg_show = stm32_pconf_dbg_show, 12398c2ecf20Sopenharmony_ci}; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_cistatic int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, 12428c2ecf20Sopenharmony_ci struct device_node *np) 12438c2ecf20Sopenharmony_ci{ 12448c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank = &pctl->banks[pctl->nbanks]; 12458c2ecf20Sopenharmony_ci int bank_ioport_nr; 12468c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range = &bank->range; 12478c2ecf20Sopenharmony_ci struct of_phandle_args args; 12488c2ecf20Sopenharmony_ci struct device *dev = pctl->dev; 12498c2ecf20Sopenharmony_ci struct resource res; 12508c2ecf20Sopenharmony_ci int npins = STM32_GPIO_PINS_PER_BANK; 12518c2ecf20Sopenharmony_ci int bank_nr, err, i = 0; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci if (!IS_ERR(bank->rstc)) 12548c2ecf20Sopenharmony_ci reset_control_deassert(bank->rstc); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci if (of_address_to_resource(np, 0, &res)) 12578c2ecf20Sopenharmony_ci return -ENODEV; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci bank->base = devm_ioremap_resource(dev, &res); 12608c2ecf20Sopenharmony_ci if (IS_ERR(bank->base)) 12618c2ecf20Sopenharmony_ci return PTR_ERR(bank->base); 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci err = clk_prepare(bank->clk); 12648c2ecf20Sopenharmony_ci if (err) { 12658c2ecf20Sopenharmony_ci dev_err(dev, "failed to prepare clk (%d)\n", err); 12668c2ecf20Sopenharmony_ci return err; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci bank->gpio_chip = stm32_gpio_template; 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci of_property_read_string(np, "st,bank-name", &bank->gpio_chip.label); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci if (!of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, i, &args)) { 12748c2ecf20Sopenharmony_ci bank_nr = args.args[1] / STM32_GPIO_PINS_PER_BANK; 12758c2ecf20Sopenharmony_ci bank->gpio_chip.base = args.args[1]; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci /* get the last defined gpio line (offset + nb of pins) */ 12788c2ecf20Sopenharmony_ci npins = args.args[0] + args.args[2]; 12798c2ecf20Sopenharmony_ci while (!of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, ++i, &args)) 12808c2ecf20Sopenharmony_ci npins = max(npins, (int)(args.args[0] + args.args[2])); 12818c2ecf20Sopenharmony_ci } else { 12828c2ecf20Sopenharmony_ci bank_nr = pctl->nbanks; 12838c2ecf20Sopenharmony_ci bank->gpio_chip.base = bank_nr * STM32_GPIO_PINS_PER_BANK; 12848c2ecf20Sopenharmony_ci range->name = bank->gpio_chip.label; 12858c2ecf20Sopenharmony_ci range->id = bank_nr; 12868c2ecf20Sopenharmony_ci range->pin_base = range->id * STM32_GPIO_PINS_PER_BANK; 12878c2ecf20Sopenharmony_ci range->base = range->id * STM32_GPIO_PINS_PER_BANK; 12888c2ecf20Sopenharmony_ci range->npins = npins; 12898c2ecf20Sopenharmony_ci range->gc = &bank->gpio_chip; 12908c2ecf20Sopenharmony_ci pinctrl_add_gpio_range(pctl->pctl_dev, 12918c2ecf20Sopenharmony_ci &pctl->banks[bank_nr].range); 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "st,bank-ioport", &bank_ioport_nr)) 12958c2ecf20Sopenharmony_ci bank_ioport_nr = bank_nr; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci bank->gpio_chip.base = bank_nr * STM32_GPIO_PINS_PER_BANK; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci bank->gpio_chip.ngpio = npins; 13008c2ecf20Sopenharmony_ci bank->gpio_chip.of_node = np; 13018c2ecf20Sopenharmony_ci bank->gpio_chip.parent = dev; 13028c2ecf20Sopenharmony_ci bank->bank_nr = bank_nr; 13038c2ecf20Sopenharmony_ci bank->bank_ioport_nr = bank_ioport_nr; 13048c2ecf20Sopenharmony_ci spin_lock_init(&bank->lock); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci if (pctl->domain) { 13078c2ecf20Sopenharmony_ci /* create irq hierarchical domain */ 13088c2ecf20Sopenharmony_ci bank->fwnode = of_node_to_fwnode(np); 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci bank->domain = irq_domain_create_hierarchy(pctl->domain, 0, STM32_GPIO_IRQ_LINE, 13118c2ecf20Sopenharmony_ci bank->fwnode, &stm32_gpio_domain_ops, 13128c2ecf20Sopenharmony_ci bank); 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci if (!bank->domain) 13158c2ecf20Sopenharmony_ci return -ENODEV; 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci err = gpiochip_add_data(&bank->gpio_chip, bank); 13198c2ecf20Sopenharmony_ci if (err) { 13208c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add gpiochip(%d)!\n", bank_nr); 13218c2ecf20Sopenharmony_ci return err; 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci dev_info(dev, "%s bank added\n", bank->gpio_chip.label); 13258c2ecf20Sopenharmony_ci return 0; 13268c2ecf20Sopenharmony_ci} 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_cistatic struct irq_domain *stm32_pctrl_get_irq_domain(struct device_node *np) 13298c2ecf20Sopenharmony_ci{ 13308c2ecf20Sopenharmony_ci struct device_node *parent; 13318c2ecf20Sopenharmony_ci struct irq_domain *domain; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci if (!of_find_property(np, "interrupt-parent", NULL)) 13348c2ecf20Sopenharmony_ci return NULL; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci parent = of_irq_find_parent(np); 13378c2ecf20Sopenharmony_ci if (!parent) 13388c2ecf20Sopenharmony_ci return ERR_PTR(-ENXIO); 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci domain = irq_find_host(parent); 13418c2ecf20Sopenharmony_ci of_node_put(parent); 13428c2ecf20Sopenharmony_ci if (!domain) 13438c2ecf20Sopenharmony_ci /* domain not registered yet */ 13448c2ecf20Sopenharmony_ci return ERR_PTR(-EPROBE_DEFER); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci return domain; 13478c2ecf20Sopenharmony_ci} 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_cistatic int stm32_pctrl_dt_setup_irq(struct platform_device *pdev, 13508c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl) 13518c2ecf20Sopenharmony_ci{ 13528c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 13538c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 13548c2ecf20Sopenharmony_ci struct regmap *rm; 13558c2ecf20Sopenharmony_ci int offset, ret, i; 13568c2ecf20Sopenharmony_ci int mask, mask_width; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci pctl->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); 13598c2ecf20Sopenharmony_ci if (IS_ERR(pctl->regmap)) 13608c2ecf20Sopenharmony_ci return PTR_ERR(pctl->regmap); 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci rm = pctl->regmap; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci ret = of_property_read_u32_index(np, "st,syscfg", 1, &offset); 13658c2ecf20Sopenharmony_ci if (ret) 13668c2ecf20Sopenharmony_ci return ret; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci ret = of_property_read_u32_index(np, "st,syscfg", 2, &mask); 13698c2ecf20Sopenharmony_ci if (ret) 13708c2ecf20Sopenharmony_ci mask = SYSCFG_IRQMUX_MASK; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci mask_width = fls(mask); 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci for (i = 0; i < STM32_GPIO_PINS_PER_BANK; i++) { 13758c2ecf20Sopenharmony_ci struct reg_field mux; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci mux.reg = offset + (i / 4) * 4; 13788c2ecf20Sopenharmony_ci mux.lsb = (i % 4) * mask_width; 13798c2ecf20Sopenharmony_ci mux.msb = mux.lsb + mask_width - 1; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci dev_dbg(dev, "irqmux%d: reg:%#x, lsb:%d, msb:%d\n", 13828c2ecf20Sopenharmony_ci i, mux.reg, mux.lsb, mux.msb); 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci pctl->irqmux[i] = devm_regmap_field_alloc(dev, rm, mux); 13858c2ecf20Sopenharmony_ci if (IS_ERR(pctl->irqmux[i])) 13868c2ecf20Sopenharmony_ci return PTR_ERR(pctl->irqmux[i]); 13878c2ecf20Sopenharmony_ci } 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci return 0; 13908c2ecf20Sopenharmony_ci} 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_cistatic int stm32_pctrl_build_state(struct platform_device *pdev) 13938c2ecf20Sopenharmony_ci{ 13948c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl = platform_get_drvdata(pdev); 13958c2ecf20Sopenharmony_ci int i; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci pctl->ngroups = pctl->npins; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci /* Allocate groups */ 14008c2ecf20Sopenharmony_ci pctl->groups = devm_kcalloc(&pdev->dev, pctl->ngroups, 14018c2ecf20Sopenharmony_ci sizeof(*pctl->groups), GFP_KERNEL); 14028c2ecf20Sopenharmony_ci if (!pctl->groups) 14038c2ecf20Sopenharmony_ci return -ENOMEM; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci /* We assume that one pin is one group, use pin name as group name. */ 14068c2ecf20Sopenharmony_ci pctl->grp_names = devm_kcalloc(&pdev->dev, pctl->ngroups, 14078c2ecf20Sopenharmony_ci sizeof(*pctl->grp_names), GFP_KERNEL); 14088c2ecf20Sopenharmony_ci if (!pctl->grp_names) 14098c2ecf20Sopenharmony_ci return -ENOMEM; 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci for (i = 0; i < pctl->npins; i++) { 14128c2ecf20Sopenharmony_ci const struct stm32_desc_pin *pin = pctl->pins + i; 14138c2ecf20Sopenharmony_ci struct stm32_pinctrl_group *group = pctl->groups + i; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci group->name = pin->pin.name; 14168c2ecf20Sopenharmony_ci group->pin = pin->pin.number; 14178c2ecf20Sopenharmony_ci pctl->grp_names[i] = pin->pin.name; 14188c2ecf20Sopenharmony_ci } 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci return 0; 14218c2ecf20Sopenharmony_ci} 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_cistatic int stm32_pctrl_create_pins_tab(struct stm32_pinctrl *pctl, 14248c2ecf20Sopenharmony_ci struct stm32_desc_pin *pins) 14258c2ecf20Sopenharmony_ci{ 14268c2ecf20Sopenharmony_ci const struct stm32_desc_pin *p; 14278c2ecf20Sopenharmony_ci int i, nb_pins_available = 0; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci for (i = 0; i < pctl->match_data->npins; i++) { 14308c2ecf20Sopenharmony_ci p = pctl->match_data->pins + i; 14318c2ecf20Sopenharmony_ci if (pctl->pkg && !(pctl->pkg & p->pkg)) 14328c2ecf20Sopenharmony_ci continue; 14338c2ecf20Sopenharmony_ci pins->pin = p->pin; 14348c2ecf20Sopenharmony_ci pins->functions = p->functions; 14358c2ecf20Sopenharmony_ci pins++; 14368c2ecf20Sopenharmony_ci nb_pins_available++; 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci pctl->npins = nb_pins_available; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci return 0; 14428c2ecf20Sopenharmony_ci} 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_cistatic void stm32_pctl_get_package(struct device_node *np, 14458c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl) 14468c2ecf20Sopenharmony_ci{ 14478c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "st,package", &pctl->pkg)) { 14488c2ecf20Sopenharmony_ci pctl->pkg = 0; 14498c2ecf20Sopenharmony_ci dev_warn(pctl->dev, "No package detected, use default one\n"); 14508c2ecf20Sopenharmony_ci } else { 14518c2ecf20Sopenharmony_ci dev_dbg(pctl->dev, "package detected: %x\n", pctl->pkg); 14528c2ecf20Sopenharmony_ci } 14538c2ecf20Sopenharmony_ci} 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ciint stm32_pctl_probe(struct platform_device *pdev) 14568c2ecf20Sopenharmony_ci{ 14578c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 14588c2ecf20Sopenharmony_ci struct device_node *child; 14598c2ecf20Sopenharmony_ci const struct of_device_id *match; 14608c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 14618c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl; 14628c2ecf20Sopenharmony_ci struct pinctrl_pin_desc *pins; 14638c2ecf20Sopenharmony_ci int i, ret, hwlock_id, banks = 0; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci if (!np) 14668c2ecf20Sopenharmony_ci return -EINVAL; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci match = of_match_device(dev->driver->of_match_table, dev); 14698c2ecf20Sopenharmony_ci if (!match || !match->data) 14708c2ecf20Sopenharmony_ci return -EINVAL; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci if (!of_find_property(np, "pins-are-numbered", NULL)) { 14738c2ecf20Sopenharmony_ci dev_err(dev, "only support pins-are-numbered format\n"); 14748c2ecf20Sopenharmony_ci return -EINVAL; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci pctl = devm_kzalloc(dev, sizeof(*pctl), GFP_KERNEL); 14788c2ecf20Sopenharmony_ci if (!pctl) 14798c2ecf20Sopenharmony_ci return -ENOMEM; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, pctl); 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci /* check for IRQ controller (may require deferred probe) */ 14848c2ecf20Sopenharmony_ci pctl->domain = stm32_pctrl_get_irq_domain(np); 14858c2ecf20Sopenharmony_ci if (IS_ERR(pctl->domain)) 14868c2ecf20Sopenharmony_ci return PTR_ERR(pctl->domain); 14878c2ecf20Sopenharmony_ci if (!pctl->domain) 14888c2ecf20Sopenharmony_ci dev_warn(dev, "pinctrl without interrupt support\n"); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci /* hwspinlock is optional */ 14918c2ecf20Sopenharmony_ci hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0); 14928c2ecf20Sopenharmony_ci if (hwlock_id < 0) { 14938c2ecf20Sopenharmony_ci if (hwlock_id == -EPROBE_DEFER) 14948c2ecf20Sopenharmony_ci return hwlock_id; 14958c2ecf20Sopenharmony_ci } else { 14968c2ecf20Sopenharmony_ci pctl->hwlock = hwspin_lock_request_specific(hwlock_id); 14978c2ecf20Sopenharmony_ci } 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci spin_lock_init(&pctl->irqmux_lock); 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci pctl->dev = dev; 15028c2ecf20Sopenharmony_ci pctl->match_data = match->data; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci /* get package information */ 15058c2ecf20Sopenharmony_ci stm32_pctl_get_package(np, pctl); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci pctl->pins = devm_kcalloc(pctl->dev, pctl->match_data->npins, 15088c2ecf20Sopenharmony_ci sizeof(*pctl->pins), GFP_KERNEL); 15098c2ecf20Sopenharmony_ci if (!pctl->pins) 15108c2ecf20Sopenharmony_ci return -ENOMEM; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci ret = stm32_pctrl_create_pins_tab(pctl, pctl->pins); 15138c2ecf20Sopenharmony_ci if (ret) 15148c2ecf20Sopenharmony_ci return ret; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci ret = stm32_pctrl_build_state(pdev); 15178c2ecf20Sopenharmony_ci if (ret) { 15188c2ecf20Sopenharmony_ci dev_err(dev, "build state failed: %d\n", ret); 15198c2ecf20Sopenharmony_ci return -EINVAL; 15208c2ecf20Sopenharmony_ci } 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci if (pctl->domain) { 15238c2ecf20Sopenharmony_ci ret = stm32_pctrl_dt_setup_irq(pdev, pctl); 15248c2ecf20Sopenharmony_ci if (ret) 15258c2ecf20Sopenharmony_ci return ret; 15268c2ecf20Sopenharmony_ci } 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci pins = devm_kcalloc(&pdev->dev, pctl->npins, sizeof(*pins), 15298c2ecf20Sopenharmony_ci GFP_KERNEL); 15308c2ecf20Sopenharmony_ci if (!pins) 15318c2ecf20Sopenharmony_ci return -ENOMEM; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci for (i = 0; i < pctl->npins; i++) 15348c2ecf20Sopenharmony_ci pins[i] = pctl->pins[i].pin; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci pctl->pctl_desc.name = dev_name(&pdev->dev); 15378c2ecf20Sopenharmony_ci pctl->pctl_desc.owner = THIS_MODULE; 15388c2ecf20Sopenharmony_ci pctl->pctl_desc.pins = pins; 15398c2ecf20Sopenharmony_ci pctl->pctl_desc.npins = pctl->npins; 15408c2ecf20Sopenharmony_ci pctl->pctl_desc.link_consumers = true; 15418c2ecf20Sopenharmony_ci pctl->pctl_desc.confops = &stm32_pconf_ops; 15428c2ecf20Sopenharmony_ci pctl->pctl_desc.pctlops = &stm32_pctrl_ops; 15438c2ecf20Sopenharmony_ci pctl->pctl_desc.pmxops = &stm32_pmx_ops; 15448c2ecf20Sopenharmony_ci pctl->dev = &pdev->dev; 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, &pctl->pctl_desc, 15478c2ecf20Sopenharmony_ci pctl); 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci if (IS_ERR(pctl->pctl_dev)) { 15508c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed pinctrl registration\n"); 15518c2ecf20Sopenharmony_ci return PTR_ERR(pctl->pctl_dev); 15528c2ecf20Sopenharmony_ci } 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci for_each_available_child_of_node(np, child) 15558c2ecf20Sopenharmony_ci if (of_property_read_bool(child, "gpio-controller")) 15568c2ecf20Sopenharmony_ci banks++; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci if (!banks) { 15598c2ecf20Sopenharmony_ci dev_err(dev, "at least one GPIO bank is required\n"); 15608c2ecf20Sopenharmony_ci return -EINVAL; 15618c2ecf20Sopenharmony_ci } 15628c2ecf20Sopenharmony_ci pctl->banks = devm_kcalloc(dev, banks, sizeof(*pctl->banks), 15638c2ecf20Sopenharmony_ci GFP_KERNEL); 15648c2ecf20Sopenharmony_ci if (!pctl->banks) 15658c2ecf20Sopenharmony_ci return -ENOMEM; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci i = 0; 15688c2ecf20Sopenharmony_ci for_each_available_child_of_node(np, child) { 15698c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank = &pctl->banks[i]; 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci if (of_property_read_bool(child, "gpio-controller")) { 15728c2ecf20Sopenharmony_ci bank->rstc = of_reset_control_get_exclusive(child, 15738c2ecf20Sopenharmony_ci NULL); 15748c2ecf20Sopenharmony_ci if (PTR_ERR(bank->rstc) == -EPROBE_DEFER) 15758c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci bank->clk = of_clk_get_by_name(child, NULL); 15788c2ecf20Sopenharmony_ci if (IS_ERR(bank->clk)) { 15798c2ecf20Sopenharmony_ci if (PTR_ERR(bank->clk) != -EPROBE_DEFER) 15808c2ecf20Sopenharmony_ci dev_err(dev, 15818c2ecf20Sopenharmony_ci "failed to get clk (%ld)\n", 15828c2ecf20Sopenharmony_ci PTR_ERR(bank->clk)); 15838c2ecf20Sopenharmony_ci return PTR_ERR(bank->clk); 15848c2ecf20Sopenharmony_ci } 15858c2ecf20Sopenharmony_ci i++; 15868c2ecf20Sopenharmony_ci } 15878c2ecf20Sopenharmony_ci } 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci for_each_available_child_of_node(np, child) { 15908c2ecf20Sopenharmony_ci if (of_property_read_bool(child, "gpio-controller")) { 15918c2ecf20Sopenharmony_ci ret = stm32_gpiolib_register_bank(pctl, child); 15928c2ecf20Sopenharmony_ci if (ret) { 15938c2ecf20Sopenharmony_ci of_node_put(child); 15948c2ecf20Sopenharmony_ci return ret; 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci pctl->nbanks++; 15988c2ecf20Sopenharmony_ci } 15998c2ecf20Sopenharmony_ci } 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci dev_info(dev, "Pinctrl STM32 initialized\n"); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci return 0; 16048c2ecf20Sopenharmony_ci} 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_cistatic int __maybe_unused stm32_pinctrl_restore_gpio_regs( 16078c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl, u32 pin) 16088c2ecf20Sopenharmony_ci{ 16098c2ecf20Sopenharmony_ci const struct pin_desc *desc = pin_desc_get(pctl->pctl_dev, pin); 16108c2ecf20Sopenharmony_ci u32 val, alt, mode, offset = stm32_gpio_pin(pin); 16118c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range; 16128c2ecf20Sopenharmony_ci struct stm32_gpio_bank *bank; 16138c2ecf20Sopenharmony_ci bool pin_is_irq; 16148c2ecf20Sopenharmony_ci int ret; 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci range = pinctrl_find_gpio_range_from_pin(pctl->pctl_dev, pin); 16178c2ecf20Sopenharmony_ci if (!range) 16188c2ecf20Sopenharmony_ci return 0; 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci pin_is_irq = gpiochip_line_is_irq(range->gc, offset); 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci if (!desc || (!pin_is_irq && !desc->gpio_owner)) 16238c2ecf20Sopenharmony_ci return 0; 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci bank = gpiochip_get_data(range->gc); 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci alt = bank->pin_backup[offset] & STM32_GPIO_BKP_ALT_MASK; 16288c2ecf20Sopenharmony_ci alt >>= STM32_GPIO_BKP_ALT_SHIFT; 16298c2ecf20Sopenharmony_ci mode = bank->pin_backup[offset] & STM32_GPIO_BKP_MODE_MASK; 16308c2ecf20Sopenharmony_ci mode >>= STM32_GPIO_BKP_MODE_SHIFT; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci ret = stm32_pmx_set_mode(bank, offset, mode, alt); 16338c2ecf20Sopenharmony_ci if (ret) 16348c2ecf20Sopenharmony_ci return ret; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci if (mode == 1) { 16378c2ecf20Sopenharmony_ci val = bank->pin_backup[offset] & BIT(STM32_GPIO_BKP_VAL); 16388c2ecf20Sopenharmony_ci val = val >> STM32_GPIO_BKP_VAL; 16398c2ecf20Sopenharmony_ci __stm32_gpio_set(bank, offset, val); 16408c2ecf20Sopenharmony_ci } 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci val = bank->pin_backup[offset] & BIT(STM32_GPIO_BKP_TYPE); 16438c2ecf20Sopenharmony_ci val >>= STM32_GPIO_BKP_TYPE; 16448c2ecf20Sopenharmony_ci ret = stm32_pconf_set_driving(bank, offset, val); 16458c2ecf20Sopenharmony_ci if (ret) 16468c2ecf20Sopenharmony_ci return ret; 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci val = bank->pin_backup[offset] & STM32_GPIO_BKP_SPEED_MASK; 16498c2ecf20Sopenharmony_ci val >>= STM32_GPIO_BKP_SPEED_SHIFT; 16508c2ecf20Sopenharmony_ci ret = stm32_pconf_set_speed(bank, offset, val); 16518c2ecf20Sopenharmony_ci if (ret) 16528c2ecf20Sopenharmony_ci return ret; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci val = bank->pin_backup[offset] & STM32_GPIO_BKP_PUPD_MASK; 16558c2ecf20Sopenharmony_ci val >>= STM32_GPIO_BKP_PUPD_SHIFT; 16568c2ecf20Sopenharmony_ci ret = stm32_pconf_set_bias(bank, offset, val); 16578c2ecf20Sopenharmony_ci if (ret) 16588c2ecf20Sopenharmony_ci return ret; 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci if (pin_is_irq) 16618c2ecf20Sopenharmony_ci regmap_field_write(pctl->irqmux[offset], bank->bank_ioport_nr); 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci return 0; 16648c2ecf20Sopenharmony_ci} 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ciint __maybe_unused stm32_pinctrl_resume(struct device *dev) 16678c2ecf20Sopenharmony_ci{ 16688c2ecf20Sopenharmony_ci struct stm32_pinctrl *pctl = dev_get_drvdata(dev); 16698c2ecf20Sopenharmony_ci struct stm32_pinctrl_group *g = pctl->groups; 16708c2ecf20Sopenharmony_ci int i; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci for (i = 0; i < pctl->ngroups; i++, g++) 16738c2ecf20Sopenharmony_ci stm32_pinctrl_restore_gpio_regs(pctl, g->pin); 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci return 0; 16768c2ecf20Sopenharmony_ci} 1677