Update Linux to v5.4.2
Change-Id: Idf6911045d9d382da2cfe01b1edff026404ac8fd
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c
index a9bec6e..2d5e043 100644
--- a/drivers/pinctrl/stm32/pinctrl-stm32.c
+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c
@@ -8,6 +8,7 @@
*/
#include <linux/clk.h>
#include <linux/gpio/driver.h>
+#include <linux/hwspinlock.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/mfd/syscon.h>
@@ -43,6 +44,18 @@
#define STM32_GPIO_AFRL 0x20
#define STM32_GPIO_AFRH 0x24
+/* custom bitfield to backup pin status */
+#define STM32_GPIO_BKP_MODE_SHIFT 0
+#define STM32_GPIO_BKP_MODE_MASK GENMASK(1, 0)
+#define STM32_GPIO_BKP_ALT_SHIFT 2
+#define STM32_GPIO_BKP_ALT_MASK GENMASK(5, 2)
+#define STM32_GPIO_BKP_SPEED_SHIFT 6
+#define STM32_GPIO_BKP_SPEED_MASK GENMASK(7, 6)
+#define STM32_GPIO_BKP_PUPD_SHIFT 8
+#define STM32_GPIO_BKP_PUPD_MASK GENMASK(9, 8)
+#define STM32_GPIO_BKP_TYPE 10
+#define STM32_GPIO_BKP_VAL 11
+
#define STM32_GPIO_PINS_PER_BANK 16
#define STM32_GPIO_IRQ_LINE 16
@@ -51,6 +64,8 @@
#define gpio_range_to_bank(chip) \
container_of(chip, struct stm32_gpio_bank, range)
+#define HWSPINLOCK_TIMEOUT 5 /* msec */
+
static const char * const stm32_gpio_functions[] = {
"gpio", "af0", "af1",
"af2", "af3", "af4",
@@ -76,6 +91,7 @@
struct irq_domain *domain;
u32 bank_nr;
u32 bank_ioport_nr;
+ u32 pin_backup[STM32_GPIO_PINS_PER_BANK];
};
struct stm32_pinctrl {
@@ -91,6 +107,12 @@
struct irq_domain *domain;
struct regmap *regmap;
struct regmap_field *irqmux[STM32_GPIO_PINS_PER_BANK];
+ struct hwspinlock *hwlock;
+ struct stm32_desc_pin *pins;
+ u32 npins;
+ u32 pkg;
+ u16 irqmux_map;
+ spinlock_t irqmux_lock;
};
static inline int stm32_gpio_pin(int gpio)
@@ -126,11 +148,50 @@
return 0;
}
+static void stm32_gpio_backup_value(struct stm32_gpio_bank *bank,
+ u32 offset, u32 value)
+{
+ bank->pin_backup[offset] &= ~BIT(STM32_GPIO_BKP_VAL);
+ bank->pin_backup[offset] |= value << STM32_GPIO_BKP_VAL;
+}
+
+static void stm32_gpio_backup_mode(struct stm32_gpio_bank *bank, u32 offset,
+ u32 mode, u32 alt)
+{
+ bank->pin_backup[offset] &= ~(STM32_GPIO_BKP_MODE_MASK |
+ STM32_GPIO_BKP_ALT_MASK);
+ bank->pin_backup[offset] |= mode << STM32_GPIO_BKP_MODE_SHIFT;
+ bank->pin_backup[offset] |= alt << STM32_GPIO_BKP_ALT_SHIFT;
+}
+
+static void stm32_gpio_backup_driving(struct stm32_gpio_bank *bank, u32 offset,
+ u32 drive)
+{
+ bank->pin_backup[offset] &= ~BIT(STM32_GPIO_BKP_TYPE);
+ bank->pin_backup[offset] |= drive << STM32_GPIO_BKP_TYPE;
+}
+
+static void stm32_gpio_backup_speed(struct stm32_gpio_bank *bank, u32 offset,
+ u32 speed)
+{
+ bank->pin_backup[offset] &= ~STM32_GPIO_BKP_SPEED_MASK;
+ bank->pin_backup[offset] |= speed << STM32_GPIO_BKP_SPEED_SHIFT;
+}
+
+static void stm32_gpio_backup_bias(struct stm32_gpio_bank *bank, u32 offset,
+ u32 bias)
+{
+ bank->pin_backup[offset] &= ~STM32_GPIO_BKP_PUPD_MASK;
+ bank->pin_backup[offset] |= bias << STM32_GPIO_BKP_PUPD_SHIFT;
+}
+
/* GPIO functions */
static inline void __stm32_gpio_set(struct stm32_gpio_bank *bank,
unsigned offset, int value)
{
+ stm32_gpio_backup_value(bank, offset, value);
+
if (!value)
offset += STM32_GPIO_PINS_PER_BANK;
@@ -300,9 +361,53 @@
{
struct stm32_gpio_bank *bank = d->host_data;
struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
+ unsigned long flags;
+ int ret = 0;
+
+ /*
+ * gpio irq mux is shared between several banks, a lock has to be done
+ * to avoid overriding.
+ */
+ spin_lock_irqsave(&pctl->irqmux_lock, flags);
+ if (pctl->hwlock)
+ ret = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT);
+
+ if (ret) {
+ dev_err(pctl->dev, "Can't get hwspinlock\n");
+ goto unlock;
+ }
+
+ if (pctl->irqmux_map & BIT(irq_data->hwirq)) {
+ dev_err(pctl->dev, "irq line %ld already requested.\n",
+ irq_data->hwirq);
+ ret = -EBUSY;
+ if (pctl->hwlock)
+ hwspin_unlock(pctl->hwlock);
+ goto unlock;
+ } else {
+ pctl->irqmux_map |= BIT(irq_data->hwirq);
+ }
regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->bank_ioport_nr);
- return 0;
+
+ if (pctl->hwlock)
+ hwspin_unlock(pctl->hwlock);
+
+unlock:
+ spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
+ return ret;
+}
+
+static void stm32_gpio_domain_deactivate(struct irq_domain *d,
+ struct irq_data *irq_data)
+{
+ struct stm32_gpio_bank *bank = d->host_data;
+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
+ unsigned long flags;
+
+ spin_lock_irqsave(&pctl->irqmux_lock, flags);
+ pctl->irqmux_map &= ~BIT(irq_data->hwirq);
+ spin_unlock_irqrestore(&pctl->irqmux_lock, flags);
}
static int stm32_gpio_domain_alloc(struct irq_domain *d,
@@ -331,6 +436,7 @@
.alloc = stm32_gpio_domain_alloc,
.free = irq_domain_free_irqs_common,
.activate = stm32_gpio_domain_activate,
+ .deactivate = stm32_gpio_domain_deactivate,
};
/* Pinctrl functions */
@@ -354,8 +460,8 @@
{
int i;
- for (i = 0; i < pctl->match_data->npins; i++) {
- const struct stm32_desc_pin *pin = pctl->match_data->pins + i;
+ for (i = 0; i < pctl->npins; i++) {
+ const struct stm32_desc_pin *pin = pctl->pins + i;
const struct stm32_desc_function *func = pin->functions;
if (pin->pin.number != pin_num)
@@ -410,14 +516,14 @@
unsigned int num_configs;
bool has_config = 0;
unsigned reserve = 0;
- int num_pins, num_funcs, maps_per_pin, i, err;
+ int num_pins, num_funcs, maps_per_pin, i, err = 0;
pctl = pinctrl_dev_get_drvdata(pctldev);
pins = of_find_property(node, "pinmux", NULL);
if (!pins) {
- dev_err(pctl->dev, "missing pins property in node %s .\n",
- node->name);
+ dev_err(pctl->dev, "missing pins property in node %pOFn .\n",
+ node);
return -EINVAL;
}
@@ -437,41 +543,45 @@
if (has_config && num_pins >= 1)
maps_per_pin++;
- if (!num_pins || !maps_per_pin)
- return -EINVAL;
+ if (!num_pins || !maps_per_pin) {
+ err = -EINVAL;
+ goto exit;
+ }
reserve = num_pins * maps_per_pin;
err = pinctrl_utils_reserve_map(pctldev, map,
reserved_maps, num_maps, reserve);
if (err)
- return err;
+ goto exit;
for (i = 0; i < num_pins; i++) {
err = of_property_read_u32_index(node, "pinmux",
i, &pinfunc);
if (err)
- return err;
+ goto exit;
pin = STM32_GET_PIN_NO(pinfunc);
func = STM32_GET_PIN_FUNC(pinfunc);
if (!stm32_pctrl_is_function_valid(pctl, pin, func)) {
dev_err(pctl->dev, "invalid function.\n");
- return -EINVAL;
+ err = -EINVAL;
+ goto exit;
}
grp = stm32_pctrl_find_group_by_pin(pctl, pin);
if (!grp) {
dev_err(pctl->dev, "unable to match pin %d to group\n",
pin);
- return -EINVAL;
+ err = -EINVAL;
+ goto exit;
}
err = stm32_pctrl_dt_node_to_map_func(pctl, pin, func, grp, map,
reserved_maps, num_maps);
if (err)
- return err;
+ goto exit;
if (has_config) {
err = pinctrl_utils_add_map_configs(pctldev, map,
@@ -479,11 +589,13 @@
configs, num_configs,
PIN_MAP_TYPE_CONFIGS_GROUP);
if (err)
- return err;
+ goto exit;
}
}
- return 0;
+exit:
+ kfree(configs);
+ return err;
}
static int stm32_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
@@ -503,6 +615,7 @@
&reserved_maps, num_maps);
if (ret < 0) {
pinctrl_utils_free_map(pctldev, *map, *num_maps);
+ of_node_put(np);
return ret;
}
}
@@ -573,17 +686,27 @@
return 0;
}
-static void stm32_pmx_set_mode(struct stm32_gpio_bank *bank,
- int pin, u32 mode, u32 alt)
+static int stm32_pmx_set_mode(struct stm32_gpio_bank *bank,
+ int pin, u32 mode, u32 alt)
{
+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
u32 val;
int alt_shift = (pin % 8) * 4;
int alt_offset = STM32_GPIO_AFRL + (pin / 8) * 4;
unsigned long flags;
+ int err = 0;
clk_enable(bank->clk);
spin_lock_irqsave(&bank->lock, flags);
+ if (pctl->hwlock)
+ err = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT);
+
+ if (err) {
+ dev_err(pctl->dev, "Can't get hwspinlock\n");
+ goto unlock;
+ }
+
val = readl_relaxed(bank->base + alt_offset);
val &= ~GENMASK(alt_shift + 3, alt_shift);
val |= (alt << alt_shift);
@@ -594,8 +717,16 @@
val |= mode << (pin * 2);
writel_relaxed(val, bank->base + STM32_GPIO_MODER);
+ if (pctl->hwlock)
+ hwspin_unlock(pctl->hwlock);
+
+ stm32_gpio_backup_mode(bank, pin, mode, alt);
+
+unlock:
spin_unlock_irqrestore(&bank->lock, flags);
clk_disable(bank->clk);
+
+ return err;
}
void stm32_pmx_get_mode(struct stm32_gpio_bank *bank, int pin, u32 *mode,
@@ -652,9 +783,7 @@
mode = stm32_gpio_get_mode(function);
alt = stm32_gpio_get_alt(function);
- stm32_pmx_set_mode(bank, pin, mode, alt);
-
- return 0;
+ return stm32_pmx_set_mode(bank, pin, mode, alt);
}
static int stm32_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
@@ -664,9 +793,7 @@
struct stm32_gpio_bank *bank = gpiochip_get_data(range->gc);
int pin = stm32_gpio_pin(gpio);
- stm32_pmx_set_mode(bank, pin, !input, 0);
-
- return 0;
+ return stm32_pmx_set_mode(bank, pin, !input, 0);
}
static const struct pinmux_ops stm32_pmx_ops = {
@@ -680,22 +807,40 @@
/* Pinconf functions */
-static void stm32_pconf_set_driving(struct stm32_gpio_bank *bank,
- unsigned offset, u32 drive)
+static int stm32_pconf_set_driving(struct stm32_gpio_bank *bank,
+ unsigned offset, u32 drive)
{
+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
unsigned long flags;
u32 val;
+ int err = 0;
clk_enable(bank->clk);
spin_lock_irqsave(&bank->lock, flags);
+ if (pctl->hwlock)
+ err = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT);
+
+ if (err) {
+ dev_err(pctl->dev, "Can't get hwspinlock\n");
+ goto unlock;
+ }
+
val = readl_relaxed(bank->base + STM32_GPIO_TYPER);
val &= ~BIT(offset);
val |= drive << offset;
writel_relaxed(val, bank->base + STM32_GPIO_TYPER);
+ if (pctl->hwlock)
+ hwspin_unlock(pctl->hwlock);
+
+ stm32_gpio_backup_driving(bank, offset, drive);
+
+unlock:
spin_unlock_irqrestore(&bank->lock, flags);
clk_disable(bank->clk);
+
+ return err;
}
static u32 stm32_pconf_get_driving(struct stm32_gpio_bank *bank,
@@ -716,22 +861,40 @@
return (val >> offset);
}
-static void stm32_pconf_set_speed(struct stm32_gpio_bank *bank,
- unsigned offset, u32 speed)
+static int stm32_pconf_set_speed(struct stm32_gpio_bank *bank,
+ unsigned offset, u32 speed)
{
+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
unsigned long flags;
u32 val;
+ int err = 0;
clk_enable(bank->clk);
spin_lock_irqsave(&bank->lock, flags);
+ if (pctl->hwlock)
+ err = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT);
+
+ if (err) {
+ dev_err(pctl->dev, "Can't get hwspinlock\n");
+ goto unlock;
+ }
+
val = readl_relaxed(bank->base + STM32_GPIO_SPEEDR);
val &= ~GENMASK(offset * 2 + 1, offset * 2);
val |= speed << (offset * 2);
writel_relaxed(val, bank->base + STM32_GPIO_SPEEDR);
+ if (pctl->hwlock)
+ hwspin_unlock(pctl->hwlock);
+
+ stm32_gpio_backup_speed(bank, offset, speed);
+
+unlock:
spin_unlock_irqrestore(&bank->lock, flags);
clk_disable(bank->clk);
+
+ return err;
}
static u32 stm32_pconf_get_speed(struct stm32_gpio_bank *bank,
@@ -752,22 +915,40 @@
return (val >> (offset * 2));
}
-static void stm32_pconf_set_bias(struct stm32_gpio_bank *bank,
- unsigned offset, u32 bias)
+static int stm32_pconf_set_bias(struct stm32_gpio_bank *bank,
+ unsigned offset, u32 bias)
{
+ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
unsigned long flags;
u32 val;
+ int err = 0;
clk_enable(bank->clk);
spin_lock_irqsave(&bank->lock, flags);
+ if (pctl->hwlock)
+ err = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT);
+
+ if (err) {
+ dev_err(pctl->dev, "Can't get hwspinlock\n");
+ goto unlock;
+ }
+
val = readl_relaxed(bank->base + STM32_GPIO_PUPDR);
val &= ~GENMASK(offset * 2 + 1, offset * 2);
val |= bias << (offset * 2);
writel_relaxed(val, bank->base + STM32_GPIO_PUPDR);
+ if (pctl->hwlock)
+ hwspin_unlock(pctl->hwlock);
+
+ stm32_gpio_backup_bias(bank, offset, bias);
+
+unlock:
spin_unlock_irqrestore(&bank->lock, flags);
clk_disable(bank->clk);
+
+ return err;
}
static u32 stm32_pconf_get_bias(struct stm32_gpio_bank *bank,
@@ -830,22 +1011,22 @@
switch (param) {
case PIN_CONFIG_DRIVE_PUSH_PULL:
- stm32_pconf_set_driving(bank, offset, 0);
+ ret = stm32_pconf_set_driving(bank, offset, 0);
break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
- stm32_pconf_set_driving(bank, offset, 1);
+ ret = stm32_pconf_set_driving(bank, offset, 1);
break;
case PIN_CONFIG_SLEW_RATE:
- stm32_pconf_set_speed(bank, offset, arg);
+ ret = stm32_pconf_set_speed(bank, offset, arg);
break;
case PIN_CONFIG_BIAS_DISABLE:
- stm32_pconf_set_bias(bank, offset, 0);
+ ret = stm32_pconf_set_bias(bank, offset, 0);
break;
case PIN_CONFIG_BIAS_PULL_UP:
- stm32_pconf_set_bias(bank, offset, 1);
+ ret = stm32_pconf_set_bias(bank, offset, 1);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
- stm32_pconf_set_bias(bank, offset, 2);
+ ret = stm32_pconf_set_bias(bank, offset, 2);
break;
case PIN_CONFIG_OUTPUT:
__stm32_gpio_set(bank, offset, arg);
@@ -1049,23 +1230,35 @@
return 0;
}
+static struct irq_domain *stm32_pctrl_get_irq_domain(struct device_node *np)
+{
+ struct device_node *parent;
+ struct irq_domain *domain;
+
+ if (!of_find_property(np, "interrupt-parent", NULL))
+ return NULL;
+
+ parent = of_irq_find_parent(np);
+ if (!parent)
+ return ERR_PTR(-ENXIO);
+
+ domain = irq_find_host(parent);
+ if (!domain)
+ /* domain not registered yet */
+ return ERR_PTR(-EPROBE_DEFER);
+
+ return domain;
+}
+
static int stm32_pctrl_dt_setup_irq(struct platform_device *pdev,
struct stm32_pinctrl *pctl)
{
- struct device_node *np = pdev->dev.of_node, *parent;
+ struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct regmap *rm;
int offset, ret, i;
int mask, mask_width;
- parent = of_irq_find_parent(np);
- if (!parent)
- return -ENXIO;
-
- pctl->domain = irq_find_host(parent);
- if (!pctl->domain)
- return -ENXIO;
-
pctl->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
if (IS_ERR(pctl->regmap))
return PTR_ERR(pctl->regmap);
@@ -1105,7 +1298,7 @@
struct stm32_pinctrl *pctl = platform_get_drvdata(pdev);
int i;
- pctl->ngroups = pctl->match_data->npins;
+ pctl->ngroups = pctl->npins;
/* Allocate groups */
pctl->groups = devm_kcalloc(&pdev->dev, pctl->ngroups,
@@ -1119,19 +1312,50 @@
if (!pctl->grp_names)
return -ENOMEM;
- for (i = 0; i < pctl->match_data->npins; i++) {
- const struct stm32_desc_pin *pin = pctl->match_data->pins + i;
+ for (i = 0; i < pctl->npins; i++) {
+ const struct stm32_desc_pin *pin = pctl->pins + i;
struct stm32_pinctrl_group *group = pctl->groups + i;
group->name = pin->pin.name;
group->pin = pin->pin.number;
-
pctl->grp_names[i] = pin->pin.name;
}
return 0;
}
+static int stm32_pctrl_create_pins_tab(struct stm32_pinctrl *pctl,
+ struct stm32_desc_pin *pins)
+{
+ const struct stm32_desc_pin *p;
+ int i, nb_pins_available = 0;
+
+ for (i = 0; i < pctl->match_data->npins; i++) {
+ p = pctl->match_data->pins + i;
+ if (pctl->pkg && !(pctl->pkg & p->pkg))
+ continue;
+ pins->pin = p->pin;
+ pins->functions = p->functions;
+ pins++;
+ nb_pins_available++;
+ }
+
+ pctl->npins = nb_pins_available;
+
+ return 0;
+}
+
+static void stm32_pctl_get_package(struct device_node *np,
+ struct stm32_pinctrl *pctl)
+{
+ if (of_property_read_u32(np, "st,package", &pctl->pkg)) {
+ pctl->pkg = 0;
+ dev_warn(pctl->dev, "No package detected, use default one\n");
+ } else {
+ dev_dbg(pctl->dev, "package detected: %x\n", pctl->pkg);
+ }
+}
+
int stm32_pctl_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -1140,7 +1364,7 @@
struct device *dev = &pdev->dev;
struct stm32_pinctrl *pctl;
struct pinctrl_pin_desc *pins;
- int i, ret, banks = 0;
+ int i, ret, hwlock_id, banks = 0;
if (!np)
return -EINVAL;
@@ -1160,32 +1384,62 @@
platform_set_drvdata(pdev, pctl);
+ /* check for IRQ controller (may require deferred probe) */
+ pctl->domain = stm32_pctrl_get_irq_domain(np);
+ if (IS_ERR(pctl->domain))
+ return PTR_ERR(pctl->domain);
+
+ /* hwspinlock is optional */
+ hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0);
+ if (hwlock_id < 0) {
+ if (hwlock_id == -EPROBE_DEFER)
+ return hwlock_id;
+ } else {
+ pctl->hwlock = hwspin_lock_request_specific(hwlock_id);
+ }
+
+ spin_lock_init(&pctl->irqmux_lock);
+
pctl->dev = dev;
pctl->match_data = match->data;
+
+ /* get package information */
+ stm32_pctl_get_package(np, pctl);
+
+ pctl->pins = devm_kcalloc(pctl->dev, pctl->match_data->npins,
+ sizeof(*pctl->pins), GFP_KERNEL);
+ if (!pctl->pins)
+ return -ENOMEM;
+
+ ret = stm32_pctrl_create_pins_tab(pctl, pctl->pins);
+ if (ret)
+ return ret;
+
ret = stm32_pctrl_build_state(pdev);
if (ret) {
dev_err(dev, "build state failed: %d\n", ret);
return -EINVAL;
}
- if (of_find_property(np, "interrupt-parent", NULL)) {
+ if (pctl->domain) {
ret = stm32_pctrl_dt_setup_irq(pdev, pctl);
if (ret)
return ret;
}
- pins = devm_kcalloc(&pdev->dev, pctl->match_data->npins, sizeof(*pins),
+ pins = devm_kcalloc(&pdev->dev, pctl->npins, sizeof(*pins),
GFP_KERNEL);
if (!pins)
return -ENOMEM;
- for (i = 0; i < pctl->match_data->npins; i++)
- pins[i] = pctl->match_data->pins[i].pin;
+ for (i = 0; i < pctl->npins; i++)
+ pins[i] = pctl->pins[i].pin;
pctl->pctl_desc.name = dev_name(&pdev->dev);
pctl->pctl_desc.owner = THIS_MODULE;
pctl->pctl_desc.pins = pins;
- pctl->pctl_desc.npins = pctl->match_data->npins;
+ pctl->pctl_desc.npins = pctl->npins;
+ pctl->pctl_desc.link_consumers = true;
pctl->pctl_desc.confops = &stm32_pconf_ops;
pctl->pctl_desc.pctlops = &stm32_pctrl_ops;
pctl->pctl_desc.pmxops = &stm32_pmx_ops;
@@ -1215,8 +1469,10 @@
for_each_available_child_of_node(np, child) {
if (of_property_read_bool(child, "gpio-controller")) {
ret = stm32_gpiolib_register_bank(pctl, child);
- if (ret)
+ if (ret) {
+ of_node_put(child);
return ret;
+ }
pctl->nbanks++;
}
@@ -1227,3 +1483,74 @@
return 0;
}
+static int __maybe_unused stm32_pinctrl_restore_gpio_regs(
+ struct stm32_pinctrl *pctl, u32 pin)
+{
+ const struct pin_desc *desc = pin_desc_get(pctl->pctl_dev, pin);
+ u32 val, alt, mode, offset = stm32_gpio_pin(pin);
+ struct pinctrl_gpio_range *range;
+ struct stm32_gpio_bank *bank;
+ bool pin_is_irq;
+ int ret;
+
+ range = pinctrl_find_gpio_range_from_pin(pctl->pctl_dev, pin);
+ if (!range)
+ return 0;
+
+ pin_is_irq = gpiochip_line_is_irq(range->gc, offset);
+
+ if (!desc || (!pin_is_irq && !desc->gpio_owner))
+ return 0;
+
+ bank = gpiochip_get_data(range->gc);
+
+ alt = bank->pin_backup[offset] & STM32_GPIO_BKP_ALT_MASK;
+ alt >>= STM32_GPIO_BKP_ALT_SHIFT;
+ mode = bank->pin_backup[offset] & STM32_GPIO_BKP_MODE_MASK;
+ mode >>= STM32_GPIO_BKP_MODE_SHIFT;
+
+ ret = stm32_pmx_set_mode(bank, offset, mode, alt);
+ if (ret)
+ return ret;
+
+ if (mode == 1) {
+ val = bank->pin_backup[offset] & BIT(STM32_GPIO_BKP_VAL);
+ val = val >> STM32_GPIO_BKP_VAL;
+ __stm32_gpio_set(bank, offset, val);
+ }
+
+ val = bank->pin_backup[offset] & BIT(STM32_GPIO_BKP_TYPE);
+ val >>= STM32_GPIO_BKP_TYPE;
+ ret = stm32_pconf_set_driving(bank, offset, val);
+ if (ret)
+ return ret;
+
+ val = bank->pin_backup[offset] & STM32_GPIO_BKP_SPEED_MASK;
+ val >>= STM32_GPIO_BKP_SPEED_SHIFT;
+ ret = stm32_pconf_set_speed(bank, offset, val);
+ if (ret)
+ return ret;
+
+ val = bank->pin_backup[offset] & STM32_GPIO_BKP_PUPD_MASK;
+ val >>= STM32_GPIO_BKP_PUPD_SHIFT;
+ ret = stm32_pconf_set_bias(bank, offset, val);
+ if (ret)
+ return ret;
+
+ if (pin_is_irq)
+ regmap_field_write(pctl->irqmux[offset], bank->bank_ioport_nr);
+
+ return 0;
+}
+
+int __maybe_unused stm32_pinctrl_resume(struct device *dev)
+{
+ struct stm32_pinctrl *pctl = dev_get_drvdata(dev);
+ struct stm32_pinctrl_group *g = pctl->groups;
+ int i;
+
+ for (i = g->pin; i < g->pin + pctl->ngroups; i++)
+ stm32_pinctrl_restore_gpio_regs(pctl, i);
+
+ return 0;
+}