The SIUL2 module is now represented as an mfd device. The pinctrl driver
is now an mfd_cell. Therefore, remove its compatible and adjust its
probing in order to get the necessary information from its mfd parent.
This change came as a result of upstream review in the following series:
https://lore.kernel.org/linux-gpio/a924bbb6-96ec-40be-9d82-a76b2ab73afd@oss.nxp.com/
https://lore.kernel.org/all/20240926143122.1385658-3-andrei.stefanescu@oss.nxp.com/
The SIUL2 module has multiple capabilities. It has support for reading
SoC information, pinctrl and GPIO. All of this functionality is part of
the same register space. The initial pinctrl driver treated the pinctrl
functionality as separate from the GPIO one. However, they do rely on
common registers and a long, detailed and specific register range list
would be required for pinctrl&GPIO (carving out the necessary memory
for each function). Moreover, in some cases this wouldn't be enough. For
example reading a GPIO's direction would require a read of the MSCR
register corresponding to that pin. This would not be possible in the
GPIO driver because all of the MSCR registers are referenced by the
pinctrl driver.
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Andrei Stefanescu <andrei.stefanescu@oss.nxp.com>
---
drivers/pinctrl/nxp/pinctrl-s32.h | 3 +-
drivers/pinctrl/nxp/pinctrl-s32cc.c | 143 ++++++++++++----------------
drivers/pinctrl/nxp/pinctrl-s32g2.c | 25 +----
3 files changed, 66 insertions(+), 105 deletions(-)
diff --git a/drivers/pinctrl/nxp/pinctrl-s32.h b/drivers/pinctrl/nxp/pinctrl-s32.h
index add3c77ddfed..d52c6f814de8 100644
--- a/drivers/pinctrl/nxp/pinctrl-s32.h
+++ b/drivers/pinctrl/nxp/pinctrl-s32.h
@@ -2,7 +2,7 @@
*
* S32 pinmux core definitions
*
- * Copyright 2016-2020, 2022 NXP
+ * Copyright 2016-2020, 2022, 2024 NXP
* Copyright (C) 2022 SUSE LLC
* Copyright 2015-2016 Freescale Semiconductor, Inc.
* Copyright (C) 2012 Linaro Ltd.
@@ -38,6 +38,7 @@ struct s32_pinctrl_soc_data {
const struct pinctrl_pin_desc *pins;
unsigned int npins;
const struct s32_pin_range *mem_pin_ranges;
+ const struct regmap **regmaps;
unsigned int mem_regions;
};
diff --git a/drivers/pinctrl/nxp/pinctrl-s32cc.c b/drivers/pinctrl/nxp/pinctrl-s32cc.c
index 501eb296c760..bb2f8127c2b7 100644
--- a/drivers/pinctrl/nxp/pinctrl-s32cc.c
+++ b/drivers/pinctrl/nxp/pinctrl-s32cc.c
@@ -12,6 +12,7 @@
#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/mfd/nxp-siul2.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -44,12 +45,6 @@ enum s32_write_type {
S32_PINCONF_OVERWRITE,
};
-static struct regmap_config s32_regmap_config = {
- .reg_bits = 32,
- .val_bits = 32,
- .reg_stride = 4,
-};
-
static u32 get_pin_no(u32 pinmux)
{
return (pinmux & S32_PIN_ID_MASK) >> S32_PIN_ID_SHIFT;
@@ -85,14 +80,15 @@ struct s32_pinctrl_context {
unsigned int *pads;
};
-/*
+/**
+ * struct s32_pinctrl - private driver data
* @dev: a pointer back to containing device
* @pctl: a pointer to the pinctrl device structure
* @regions: reserved memory regions with start/end pin
* @info: structure containing information about the pin
* @gpio_configs: Saved configurations for GPIO pins
- * @gpiop_configs_lock: lock for the `gpio_configs` list
- * @s32_pinctrl_context: Configuration saved over system sleep
+ * @gpio_configs_lock: lock for the `gpio_configs` list
+ * @saved_context: Configuration saved over system sleep
*/
struct s32_pinctrl {
struct device *dev;
@@ -123,14 +119,13 @@ s32_get_region(struct pinctrl_dev *pctldev, unsigned int pin)
return NULL;
}
-static inline int s32_check_pin(struct pinctrl_dev *pctldev,
- unsigned int pin)
+static int s32_check_pin(struct pinctrl_dev *pctldev, unsigned int pin)
{
return s32_get_region(pctldev, pin) ? 0 : -EINVAL;
}
-static inline int s32_regmap_read(struct pinctrl_dev *pctldev,
- unsigned int pin, unsigned int *val)
+static int s32_regmap_read(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned int *val)
{
struct s32_pinctrl_mem_region *region;
unsigned int offset;
@@ -145,7 +140,7 @@ static inline int s32_regmap_read(struct pinctrl_dev *pctldev,
return regmap_read(region->map, offset, val);
}
-static inline int s32_regmap_write(struct pinctrl_dev *pctldev,
+static int s32_regmap_write(struct pinctrl_dev *pctldev,
unsigned int pin,
unsigned int val)
{
@@ -163,7 +158,7 @@ static inline int s32_regmap_write(struct pinctrl_dev *pctldev,
}
-static inline int s32_regmap_update(struct pinctrl_dev *pctldev, unsigned int pin,
+static int s32_regmap_update(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned int mask, unsigned int val)
{
struct s32_pinctrl_mem_region *region;
@@ -236,10 +231,10 @@ static int s32_dt_group_node_to_map(struct pinctrl_dev *pctldev,
}
ret = pinconf_generic_parse_dt_config(np, pctldev, &cfgs, &n_cfgs);
- if (ret) {
- dev_err(dev, "%pOF: could not parse node property\n", np);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "%pOF: could not parse node property\n",
+ np);
if (n_cfgs)
reserve++;
@@ -321,7 +316,7 @@ static int s32_pmx_set(struct pinctrl_dev *pctldev, unsigned int selector,
/* Check beforehand so we don't have a partial config. */
for (i = 0; i < grp->data.npins; i++) {
if (s32_check_pin(pctldev, grp->data.pins[i]) != 0) {
- dev_err(info->dev, "invalid pin: %u in group: %u\n",
+ dev_err(info->dev, "Invalid pin: %u in group: %u\n",
grp->data.pins[i], group);
return -EINVAL;
}
@@ -475,8 +470,8 @@ static int s32_get_slew_regval(int arg)
return -EINVAL;
}
-static inline void s32_pin_set_pull(enum pin_config_param param,
- unsigned int *mask, unsigned int *config)
+static void s32_pin_set_pull(enum pin_config_param param,
+ unsigned int *mask, unsigned int *config)
{
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
@@ -762,15 +757,15 @@ static int s32_pinctrl_parse_groups(struct device_node *np,
grp->data.name = np->name;
npins = of_property_count_elems_of_size(np, "pinmux", sizeof(u32));
- if (npins < 0) {
- dev_err(dev, "Failed to read 'pinmux' property in node %s.\n",
- grp->data.name);
- return -EINVAL;
- }
- if (!npins) {
- dev_err(dev, "The group %s has no pins.\n", grp->data.name);
- return -EINVAL;
- }
+ if (npins < 0)
+ return dev_err_probe(dev, -EINVAL,
+ "Failed to read 'pinmux' in node %s\n",
+ grp->data.name);
+
+ if (!npins)
+ return dev_err_probe(dev, -EINVAL,
+ "The group %s has no pins\n",
+ grp->data.name);
grp->data.npins = npins;
@@ -811,11 +806,9 @@ static int s32_pinctrl_parse_functions(struct device_node *np,
/* Initialise function */
func->name = np->name;
func->ngroups = of_get_child_count(np);
- if (func->ngroups == 0) {
- dev_err(info->dev, "no groups defined in %pOF\n", np);
- return -EINVAL;
- }
-
+ if (func->ngroups == 0)
+ return dev_err_probe(info->dev, -EINVAL,
+ "No groups defined in %pOF\n", np);
groups = devm_kcalloc(info->dev, func->ngroups,
sizeof(*func->groups), GFP_KERNEL);
if (!groups)
@@ -838,57 +831,42 @@ static int s32_pinctrl_parse_functions(struct device_node *np,
static int s32_pinctrl_probe_dt(struct platform_device *pdev,
struct s32_pinctrl *ipctl)
{
+ struct nxp_siul2_mfd *mfd = dev_get_drvdata(pdev->dev.parent);
struct s32_pinctrl_soc_info *info = ipctl->info;
- struct device_node *np = pdev->dev.of_node;
- struct resource *res;
- struct regmap *map;
- void __iomem *base;
- unsigned int mem_regions = info->soc_data->mem_regions;
+ unsigned int mem_regions;
+ struct device_node *np;
+ u32 nfuncs = 0, i = 0, j;
+ u8 regmap_type;
int ret;
- u32 nfuncs = 0;
- u32 i = 0;
+ np = pdev->dev.parent->of_node;
if (!np)
return -ENODEV;
- if (mem_regions == 0 || mem_regions >= 10000) {
- dev_err(&pdev->dev, "mem_regions is invalid: %u\n", mem_regions);
- return -EINVAL;
- }
+ /* one MSCR and one IMCR region per SIUL2 module */
+ mem_regions = info->soc_data->mem_regions;
+ if (mem_regions != mfd->num_siul2 * 2)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "Mem_regions is invalid: %u\n",
+ mem_regions);
ipctl->regions = devm_kcalloc(&pdev->dev, mem_regions,
sizeof(*ipctl->regions), GFP_KERNEL);
if (!ipctl->regions)
return -ENOMEM;
+ /* Order is MSCR regions first, then IMCR ones */
for (i = 0; i < mem_regions; i++) {
- base = devm_platform_get_and_ioremap_resource(pdev, i, &res);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- snprintf(ipctl->regions[i].name,
- sizeof(ipctl->regions[i].name), "map%u", i);
-
- s32_regmap_config.name = ipctl->regions[i].name;
- s32_regmap_config.max_register = resource_size(res) -
- s32_regmap_config.reg_stride;
-
- map = devm_regmap_init_mmio(&pdev->dev, base,
- &s32_regmap_config);
- if (IS_ERR(map)) {
- dev_err(&pdev->dev, "Failed to init regmap[%u]\n", i);
- return PTR_ERR(map);
- }
-
- ipctl->regions[i].map = map;
+ regmap_type = i < mem_regions / 2 ? SIUL2_MSCR : SIUL2_IMCR;
+ j = i % mfd->num_siul2;
+ ipctl->regions[i].map = mfd->siul2[j].regmaps[regmap_type];
ipctl->regions[i].pin_range = &info->soc_data->mem_pin_ranges[i];
}
nfuncs = of_get_child_count(np);
- if (nfuncs <= 0) {
- dev_err(&pdev->dev, "no functions defined\n");
- return -EINVAL;
- }
+ if (nfuncs <= 0)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "No functions defined\n");
info->nfunctions = nfuncs;
info->functions = devm_kcalloc(&pdev->dev, nfuncs,
@@ -918,18 +896,17 @@ static int s32_pinctrl_probe_dt(struct platform_device *pdev,
int s32_pinctrl_probe(struct platform_device *pdev,
const struct s32_pinctrl_soc_data *soc_data)
{
- struct s32_pinctrl *ipctl;
- int ret;
- struct pinctrl_desc *s32_pinctrl_desc;
- struct s32_pinctrl_soc_info *info;
#ifdef CONFIG_PM_SLEEP
struct s32_pinctrl_context *saved_context;
#endif
+ struct pinctrl_desc *s32_pinctrl_desc;
+ struct s32_pinctrl_soc_info *info;
+ struct s32_pinctrl *ipctl;
+ int ret;
- if (!soc_data || !soc_data->pins || !soc_data->npins) {
- dev_err(&pdev->dev, "wrong pinctrl info\n");
- return -EINVAL;
- }
+ if (!soc_data || !soc_data->pins || !soc_data->npins)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "Wrong pinctrl info\n");
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info)
@@ -964,17 +941,15 @@ int s32_pinctrl_probe(struct platform_device *pdev,
s32_pinctrl_desc->owner = THIS_MODULE;
ret = s32_pinctrl_probe_dt(pdev, ipctl);
- if (ret) {
- dev_err(&pdev->dev, "fail to probe dt properties\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to probe dt properties\n");
ipctl->pctl = devm_pinctrl_register(&pdev->dev, s32_pinctrl_desc,
ipctl);
if (IS_ERR(ipctl->pctl))
return dev_err_probe(&pdev->dev, PTR_ERR(ipctl->pctl),
- "could not register s32 pinctrl driver\n");
-
+ "Could not register s32 pinctrl driver\n");
#ifdef CONFIG_PM_SLEEP
saved_context = &ipctl->saved_context;
saved_context->pads =
diff --git a/drivers/pinctrl/nxp/pinctrl-s32g2.c b/drivers/pinctrl/nxp/pinctrl-s32g2.c
index 440ff1879424..27669991c339 100644
--- a/drivers/pinctrl/nxp/pinctrl-s32g2.c
+++ b/drivers/pinctrl/nxp/pinctrl-s32g2.c
@@ -3,13 +3,14 @@
* NXP S32G pinctrl driver
*
* Copyright 2015-2016 Freescale Semiconductor, Inc.
- * Copyright 2017-2018, 2020-2022 NXP
+ * Copyright 2017-2018, 2020-2022, 2024 NXP
* Copyright (C) 2022 SUSE LLC
*/
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/mfd/nxp-siul2.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -713,12 +714,10 @@ static const struct pinctrl_pin_desc s32_pinctrl_pads_siul2[] = {
static const struct s32_pin_range s32_pin_ranges_siul2[] = {
/* MSCR pin ID ranges */
S32_PIN_RANGE(0, 101),
- S32_PIN_RANGE(112, 122),
- S32_PIN_RANGE(144, 190),
+ S32_PIN_RANGE(112, 190),
/* IMCR pin ID ranges */
S32_PIN_RANGE(512, 595),
- S32_PIN_RANGE(631, 909),
- S32_PIN_RANGE(942, 1007),
+ S32_PIN_RANGE(631, 1007),
};
static const struct s32_pinctrl_soc_data s32_pinctrl_data = {
@@ -728,22 +727,9 @@ static const struct s32_pinctrl_soc_data s32_pinctrl_data = {
.mem_regions = ARRAY_SIZE(s32_pin_ranges_siul2),
};
-static const struct of_device_id s32_pinctrl_of_match[] = {
- {
- .compatible = "nxp,s32g2-siul2-pinctrl",
- .data = &s32_pinctrl_data,
- },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, s32_pinctrl_of_match);
-
static int s32g_pinctrl_probe(struct platform_device *pdev)
{
- const struct s32_pinctrl_soc_data *soc_data;
-
- soc_data = of_device_get_match_data(&pdev->dev);
-
- return s32_pinctrl_probe(pdev, soc_data);
+ return s32_pinctrl_probe(pdev, &s32_pinctrl_data);
}
static const struct dev_pm_ops s32g_pinctrl_pm_ops = {
@@ -753,7 +739,6 @@ static const struct dev_pm_ops s32g_pinctrl_pm_ops = {
static struct platform_driver s32g_pinctrl_driver = {
.driver = {
.name = "s32g-siul2-pinctrl",
- .of_match_table = s32_pinctrl_of_match,
.pm = pm_sleep_ptr(&s32g_pinctrl_pm_ops),
.suppress_bind_attrs = true,
},
--
2.45.2
On 13/11/2024 11:10, Andrei Stefanescu wrote: > > -static inline void s32_pin_set_pull(enum pin_config_param param, > - unsigned int *mask, unsigned int *config) > +static void s32_pin_set_pull(enum pin_config_param param, > + unsigned int *mask, unsigned int *config) > { > switch (param) { > case PIN_CONFIG_BIAS_DISABLE: > @@ -762,15 +757,15 @@ static int s32_pinctrl_parse_groups(struct device_node *np, > grp->data.name = np->name; > > npins = of_property_count_elems_of_size(np, "pinmux", sizeof(u32)); > - if (npins < 0) { > - dev_err(dev, "Failed to read 'pinmux' property in node %s.\n", > - grp->data.name); > - return -EINVAL; > - } > - if (!npins) { > - dev_err(dev, "The group %s has no pins.\n", grp->data.name); > - return -EINVAL; > - } > + if (npins < 0) > + return dev_err_probe(dev, -EINVAL, > + "Failed to read 'pinmux' in node %s\n", > + grp->data.name); I do not see how this change is related. Looks you are mixing cleanups with refactoring into MFD cell. These are two different things. > + > + if (!npins) > + return dev_err_probe(dev, -EINVAL, > + "The group %s has no pins\n", > + grp->data.name); > > grp->data.npins = npins; > > @@ -811,11 +806,9 @@ static int s32_pinctrl_parse_functions(struct device_node *np, > /* Initialise function */ > func->name = np->name; > func->ngroups = of_get_child_count(np); > - if (func->ngroups == 0) { > - dev_err(info->dev, "no groups defined in %pOF\n", np); > - return -EINVAL; > - } > - > + if (func->ngroups == 0) > + return dev_err_probe(info->dev, -EINVAL, > + "No groups defined in %pOF\n", np); > groups = devm_kcalloc(info->dev, func->ngroups, > sizeof(*func->groups), GFP_KERNEL); > if (!groups) > @@ -838,57 +831,42 @@ static int s32_pinctrl_parse_functions(struct device_node *np, > static int s32_pinctrl_probe_dt(struct platform_device *pdev, > struct s32_pinctrl *ipctl) > { > + struct nxp_siul2_mfd *mfd = dev_get_drvdata(pdev->dev.parent); > struct s32_pinctrl_soc_info *info = ipctl->info; > - struct device_node *np = pdev->dev.of_node; > - struct resource *res; > - struct regmap *map; > - void __iomem *base; > - unsigned int mem_regions = info->soc_data->mem_regions; > + unsigned int mem_regions; > + struct device_node *np; > + u32 nfuncs = 0, i = 0, j; > + u8 regmap_type; > int ret; > - u32 nfuncs = 0; > - u32 i = 0; > > + np = pdev->dev.parent->of_node; > if (!np) > return -ENODEV; > > - if (mem_regions == 0 || mem_regions >= 10000) { > - dev_err(&pdev->dev, "mem_regions is invalid: %u\n", mem_regions); > - return -EINVAL; > - } > + /* one MSCR and one IMCR region per SIUL2 module */ How is this related to converion into MFD cell? Still looks like an ABI break. Best regards, Krzysztof
Hi Krzysztof, >> + if (npins < 0) >> + return dev_err_probe(dev, -EINVAL, >> + "Failed to read 'pinmux' in node %s\n", >> + grp->data.name); > > I do not see how this change is related. Looks you are mixing cleanups > with refactoring into MFD cell. These are two different things. Yes, I also included some small refactoring changes. I didn't think they were important enough to include them in a separate commit. Would you like me to separate them in another commit? >> - if (mem_regions == 0 || mem_regions >= 10000) { >> - dev_err(&pdev->dev, "mem_regions is invalid: %u\n", mem_regions); >> - return -EINVAL; >> - } >> + /* one MSCR and one IMCR region per SIUL2 module */ > > How is this related to converion into MFD cell? We no longer parse the device tree to configure the regmaps, we instead get them from the mfd driver. This is the main point of converting this driver into an mfd cell. > > Still looks like an ABI break. > Yes, the driver no longer adheres to the nxp,s32g2-siul2-pinctrl.yaml binding. The intention is to deprecate that binding since it doesn't correctly describe the hardware. I am not sure on how to do this. I thought that changing this driver and removing the old compatible would be enough. Would it be better to add another file which would contain the old probing function(and match the old binding) so clients would be able to select the old implementation? > > Best regards, > Krzysztof > Best regards, Andrei
On 19/11/2024 10:57, Andrei Stefanescu wrote: > Hi Krzysztof, > >>> + if (npins < 0) >>> + return dev_err_probe(dev, -EINVAL, >>> + "Failed to read 'pinmux' in node %s\n", >>> + grp->data.name); >> >> I do not see how this change is related. Looks you are mixing cleanups >> with refactoring into MFD cell. These are two different things. > > Yes, I also included some small refactoring changes. I didn't think they were > important enough to include them in a separate commit. Would you like me to separate > them in another commit? You cannot include such changes along other, meaningful changes. This does not apply to this patch only but all contributions. There is a clear policy how cleanups, bugs and new things are being upstreamed: https://elixir.bootlin.com/linux/v6.12/source/Documentation/process/submitting-patches.rst#L168 Please read above document very carefully. This is v6 and we still circle around absolute basics. > >>> - if (mem_regions == 0 || mem_regions >= 10000) { >>> - dev_err(&pdev->dev, "mem_regions is invalid: %u\n", mem_regions); >>> - return -EINVAL; >>> - } >>> + /* one MSCR and one IMCR region per SIUL2 module */ >> >> How is this related to converion into MFD cell? > > We no longer parse the device tree to configure the regmaps, we instead > get them from the mfd driver. This is the main point of converting this > driver into an mfd cell. > >> >> Still looks like an ABI break. >> > > Yes, the driver no longer adheres to the nxp,s32g2-siul2-pinctrl.yaml binding. I did not find in commit msg explanation that this is ABI break and why it is allowed. I asked for it. > > The intention is to deprecate that binding since it doesn't correctly describe > the hardware. I am not sure on how to do this. I thought that changing this > driver and removing the old compatible would be enough. No, you cannot break the ABI. Either you deprecate this or just don't touch. > > Would it be better to add another file which would contain the old probing > function(and match the old binding) so clients would be able to select the > old implementation? I don't understand that. Your driver is supposed to keep ABI. Not through some selection but just as is. Best regards, Krzysztof
Hi Krzysztof, >>>> + if (npins < 0) >>>> + return dev_err_probe(dev, -EINVAL, >>>> + "Failed to read 'pinmux' in node %s\n", >>>> + grp->data.name); >>> >>> I do not see how this change is related. Looks you are mixing cleanups >>> with refactoring into MFD cell. These are two different things. >> >> Yes, I also included some small refactoring changes. I didn't think they were >> important enough to include them in a separate commit. Would you like me to separate >> them in another commit? > > You cannot include such changes along other, meaningful changes. This > does not apply to this patch only but all contributions. There is a > clear policy how cleanups, bugs and new things are being upstreamed: > https://elixir.bootlin.com/linux/v6.12/source/Documentation/process/submitting-patches.rst#L168 > > Please read above document very carefully. This is v6 and we still > circle around absolute basics. I will split these changes in two commits in v7. > >> >>>> - if (mem_regions == 0 || mem_regions >= 10000) { >>>> - dev_err(&pdev->dev, "mem_regions is invalid: %u\n", mem_regions); >>>> - return -EINVAL; >>>> - } >>>> + /* one MSCR and one IMCR region per SIUL2 module */ >>> >>> How is this related to converion into MFD cell? >> >> We no longer parse the device tree to configure the regmaps, we instead >> get them from the mfd driver. This is the main point of converting this >> driver into an mfd cell. >> >>> >>> Still looks like an ABI break. >>> >> >> Yes, the driver no longer adheres to the nxp,s32g2-siul2-pinctrl.yaml binding. > > I did not find in commit msg explanation that this is ABI break and why > it is allowed. I asked for it. I will explicitly mention this in v7. > >> >> The intention is to deprecate that binding since it doesn't correctly describe >> the hardware. I am not sure on how to do this. I thought that changing this >> driver and removing the old compatible would be enough. > > No, you cannot break the ABI. Either you deprecate this or just don't touch. Yes, I would like to deprecate the binding. I am not sure on how to do this. I saw that some bindings have a "deprecated: true" property at the top-level. Should I also add a commit which does that in v7 or are there other steps for deprecating a binding? Best regards, Andrei
© 2016 - 2024 Red Hat, Inc.