From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Prathamesh Shete <pshete@nvidia.com>,
Linus Walleij <linus.walleij@linaro.org>,
Sasha Levin <sashal@kernel.org>,
thierry.reding@gmail.com, jonathanh@nvidia.com, brgl@bgdev.pl,
peng.fan@nxp.com, kunwu.chan@linux.dev, dan.carpenter@linaro.org,
linux-gpio@vger.kernel.org, linux-tegra@vger.kernel.org
Subject: [PATCH AUTOSEL 6.1 060/212] pinctrl-tegra: Restore SFSEL bit when freeing pins
Date: Mon, 5 May 2025 19:03:52 -0400 [thread overview]
Message-ID: <20250505230624.2692522-60-sashal@kernel.org> (raw)
In-Reply-To: <20250505230624.2692522-1-sashal@kernel.org>
From: Prathamesh Shete <pshete@nvidia.com>
[ Upstream commit c12bfa0fee65940b10ff5187349f76c6f6b1df9c ]
Each pin can be configured as a Special Function IO (SFIO) or GPIO,
where the SFIO enables the pin to operate in alternative modes such as
I2C, SPI, etc.
The current implementation sets all the pins back to SFIO mode
even if they were initially in GPIO mode. This can cause glitches
on the pins when pinctrl_gpio_free() is called.
Avoid these undesired glitches by storing the pin's SFIO/GPIO
state on GPIO request and restoring it on GPIO free.
Signed-off-by: Prathamesh Shete <pshete@nvidia.com>
Link: https://lore.kernel.org/20250305104939.15168-2-pshete@nvidia.com
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/pinctrl/tegra/pinctrl-tegra.c | 59 +++++++++++++++++++++++----
drivers/pinctrl/tegra/pinctrl-tegra.h | 6 +++
2 files changed, 57 insertions(+), 8 deletions(-)
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
index 30341c43da59a..ba7bcc876e304 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
@@ -278,8 +278,8 @@ static int tegra_pinctrl_set_mux(struct pinctrl_dev *pctldev,
return 0;
}
-static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev *pctldev,
- unsigned int offset)
+static int tegra_pinctrl_get_group_index(struct pinctrl_dev *pctldev,
+ unsigned int offset)
{
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
unsigned int group, num_pins, j;
@@ -292,12 +292,35 @@ static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev *
continue;
for (j = 0; j < num_pins; j++) {
if (offset == pins[j])
- return &pmx->soc->groups[group];
+ return group;
}
}
- dev_err(pctldev->dev, "Pingroup not found for pin %u\n", offset);
- return NULL;
+ return -EINVAL;
+}
+
+static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev *pctldev,
+ unsigned int offset,
+ int group_index)
+{
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ if (group_index < 0 || group_index > pmx->soc->ngroups)
+ return NULL;
+
+ return &pmx->soc->groups[group_index];
+}
+
+static struct tegra_pingroup_config *tegra_pinctrl_get_group_config(struct pinctrl_dev *pctldev,
+ unsigned int offset,
+ int group_index)
+{
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ if (group_index < 0)
+ return NULL;
+
+ return &pmx->pingroup_configs[group_index];
}
static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev,
@@ -306,12 +329,15 @@ static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev,
{
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
const struct tegra_pingroup *group;
+ struct tegra_pingroup_config *config;
+ int group_index;
u32 value;
if (!pmx->soc->sfsel_in_mux)
return 0;
- group = tegra_pinctrl_get_group(pctldev, offset);
+ group_index = tegra_pinctrl_get_group_index(pctldev, offset);
+ group = tegra_pinctrl_get_group(pctldev, offset, group_index);
if (!group)
return -EINVAL;
@@ -319,7 +345,11 @@ static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev,
if (group->mux_reg < 0 || group->sfsel_bit < 0)
return -EINVAL;
+ config = tegra_pinctrl_get_group_config(pctldev, offset, group_index);
+ if (!config)
+ return -EINVAL;
value = pmx_readl(pmx, group->mux_bank, group->mux_reg);
+ config->is_sfsel = (value & BIT(group->sfsel_bit)) != 0;
value &= ~BIT(group->sfsel_bit);
pmx_writel(pmx, value, group->mux_bank, group->mux_reg);
@@ -332,12 +362,15 @@ static void tegra_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev,
{
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
const struct tegra_pingroup *group;
+ struct tegra_pingroup_config *config;
+ int group_index;
u32 value;
if (!pmx->soc->sfsel_in_mux)
return;
- group = tegra_pinctrl_get_group(pctldev, offset);
+ group_index = tegra_pinctrl_get_group_index(pctldev, offset);
+ group = tegra_pinctrl_get_group(pctldev, offset, group_index);
if (!group)
return;
@@ -345,8 +378,12 @@ static void tegra_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev,
if (group->mux_reg < 0 || group->sfsel_bit < 0)
return;
+ config = tegra_pinctrl_get_group_config(pctldev, offset, group_index);
+ if (!config)
+ return;
value = pmx_readl(pmx, group->mux_bank, group->mux_reg);
- value |= BIT(group->sfsel_bit);
+ if (config->is_sfsel)
+ value |= BIT(group->sfsel_bit);
pmx_writel(pmx, value, group->mux_bank, group->mux_reg);
}
@@ -799,6 +836,12 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
pmx->dev = &pdev->dev;
pmx->soc = soc_data;
+ pmx->pingroup_configs = devm_kcalloc(&pdev->dev,
+ pmx->soc->ngroups, sizeof(*pmx->pingroup_configs),
+ GFP_KERNEL);
+ if (!pmx->pingroup_configs)
+ return -ENOMEM;
+
/*
* Each mux group will appear in 4 functions' list of groups.
* This over-allocates slightly, since not all groups are mux groups.
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.h b/drivers/pinctrl/tegra/pinctrl-tegra.h
index f8269858eb78a..ec5198d391ea5 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra.h
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.h
@@ -8,6 +8,10 @@
#ifndef __PINMUX_TEGRA_H__
#define __PINMUX_TEGRA_H__
+struct tegra_pingroup_config {
+ bool is_sfsel;
+};
+
struct tegra_pmx {
struct device *dev;
struct pinctrl_dev *pctl;
@@ -18,6 +22,8 @@ struct tegra_pmx {
int nbanks;
void __iomem **regs;
u32 *backup_regs;
+ /* Array of size soc->ngroups */
+ struct tegra_pingroup_config *pingroup_configs;
};
enum tegra_pinconf_param {
--
2.39.5
next parent reply other threads:[~2025-05-05 23:08 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20250505230624.2692522-1-sashal@kernel.org>
2025-05-05 23:03 ` Sasha Levin [this message]
2025-05-05 23:04 ` [PATCH AUTOSEL 6.1 078/212] cpufreq: tegra186: Share policy per cluster Sasha Levin
2025-05-05 23:04 ` [PATCH AUTOSEL 6.1 080/212] arm64: tegra: p2597: Fix gpio for vdd-1v8-dis regulator Sasha Levin
2025-05-05 23:04 ` [PATCH AUTOSEL 6.1 086/212] ARM: tegra: Switch DSI-B clock parent to PLLD on Tegra114 Sasha Levin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250505230624.2692522-60-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=brgl@bgdev.pl \
--cc=dan.carpenter@linaro.org \
--cc=jonathanh@nvidia.com \
--cc=kunwu.chan@linux.dev \
--cc=linus.walleij@linaro.org \
--cc=linux-gpio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-tegra@vger.kernel.org \
--cc=peng.fan@nxp.com \
--cc=pshete@nvidia.com \
--cc=stable@vger.kernel.org \
--cc=thierry.reding@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox