Skip to content

Commit c12bfa0

Browse files
Prathamesh Shetelinusw
authored andcommitted
pinctrl-tegra: Restore SFSEL bit when freeing pins
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>
1 parent 4fd41e7 commit c12bfa0

File tree

2 files changed

+57
-8
lines changed

2 files changed

+57
-8
lines changed

drivers/pinctrl/tegra/pinctrl-tegra.c

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,8 @@ static int tegra_pinctrl_set_mux(struct pinctrl_dev *pctldev,
276276
return 0;
277277
}
278278

279-
static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev *pctldev,
280-
unsigned int offset)
279+
static int tegra_pinctrl_get_group_index(struct pinctrl_dev *pctldev,
280+
unsigned int offset)
281281
{
282282
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
283283
unsigned int group, num_pins, j;
@@ -290,12 +290,35 @@ static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev *
290290
continue;
291291
for (j = 0; j < num_pins; j++) {
292292
if (offset == pins[j])
293-
return &pmx->soc->groups[group];
293+
return group;
294294
}
295295
}
296296

297-
dev_err(pctldev->dev, "Pingroup not found for pin %u\n", offset);
298-
return NULL;
297+
return -EINVAL;
298+
}
299+
300+
static const struct tegra_pingroup *tegra_pinctrl_get_group(struct pinctrl_dev *pctldev,
301+
unsigned int offset,
302+
int group_index)
303+
{
304+
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
305+
306+
if (group_index < 0 || group_index > pmx->soc->ngroups)
307+
return NULL;
308+
309+
return &pmx->soc->groups[group_index];
310+
}
311+
312+
static struct tegra_pingroup_config *tegra_pinctrl_get_group_config(struct pinctrl_dev *pctldev,
313+
unsigned int offset,
314+
int group_index)
315+
{
316+
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
317+
318+
if (group_index < 0)
319+
return NULL;
320+
321+
return &pmx->pingroup_configs[group_index];
299322
}
300323

301324
static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev,
@@ -304,20 +327,27 @@ static int tegra_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev,
304327
{
305328
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
306329
const struct tegra_pingroup *group;
330+
struct tegra_pingroup_config *config;
331+
int group_index;
307332
u32 value;
308333

309334
if (!pmx->soc->sfsel_in_mux)
310335
return 0;
311336

312-
group = tegra_pinctrl_get_group(pctldev, offset);
337+
group_index = tegra_pinctrl_get_group_index(pctldev, offset);
338+
group = tegra_pinctrl_get_group(pctldev, offset, group_index);
313339

314340
if (!group)
315341
return -EINVAL;
316342

317343
if (group->mux_reg < 0 || group->sfsel_bit < 0)
318344
return -EINVAL;
319345

346+
config = tegra_pinctrl_get_group_config(pctldev, offset, group_index);
347+
if (!config)
348+
return -EINVAL;
320349
value = pmx_readl(pmx, group->mux_bank, group->mux_reg);
350+
config->is_sfsel = (value & BIT(group->sfsel_bit)) != 0;
321351
value &= ~BIT(group->sfsel_bit);
322352
pmx_writel(pmx, value, group->mux_bank, group->mux_reg);
323353

@@ -330,21 +360,28 @@ static void tegra_pinctrl_gpio_disable_free(struct pinctrl_dev *pctldev,
330360
{
331361
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
332362
const struct tegra_pingroup *group;
363+
struct tegra_pingroup_config *config;
364+
int group_index;
333365
u32 value;
334366

335367
if (!pmx->soc->sfsel_in_mux)
336368
return;
337369

338-
group = tegra_pinctrl_get_group(pctldev, offset);
370+
group_index = tegra_pinctrl_get_group_index(pctldev, offset);
371+
group = tegra_pinctrl_get_group(pctldev, offset, group_index);
339372

340373
if (!group)
341374
return;
342375

343376
if (group->mux_reg < 0 || group->sfsel_bit < 0)
344377
return;
345378

379+
config = tegra_pinctrl_get_group_config(pctldev, offset, group_index);
380+
if (!config)
381+
return;
346382
value = pmx_readl(pmx, group->mux_bank, group->mux_reg);
347-
value |= BIT(group->sfsel_bit);
383+
if (config->is_sfsel)
384+
value |= BIT(group->sfsel_bit);
348385
pmx_writel(pmx, value, group->mux_bank, group->mux_reg);
349386
}
350387

@@ -799,6 +836,12 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
799836
pmx->dev = &pdev->dev;
800837
pmx->soc = soc_data;
801838

839+
pmx->pingroup_configs = devm_kcalloc(&pdev->dev,
840+
pmx->soc->ngroups, sizeof(*pmx->pingroup_configs),
841+
GFP_KERNEL);
842+
if (!pmx->pingroup_configs)
843+
return -ENOMEM;
844+
802845
/*
803846
* Each mux group will appear in 4 functions' list of groups.
804847
* This over-allocates slightly, since not all groups are mux groups.

drivers/pinctrl/tegra/pinctrl-tegra.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
#ifndef __PINMUX_TEGRA_H__
99
#define __PINMUX_TEGRA_H__
1010

11+
struct tegra_pingroup_config {
12+
bool is_sfsel;
13+
};
14+
1115
struct tegra_pmx {
1216
struct device *dev;
1317
struct pinctrl_dev *pctl;
@@ -21,6 +25,8 @@ struct tegra_pmx {
2125
int nbanks;
2226
void __iomem **regs;
2327
u32 *backup_regs;
28+
/* Array of size soc->ngroups */
29+
struct tegra_pingroup_config *pingroup_configs;
2430
};
2531

2632
enum tegra_pinconf_param {

0 commit comments

Comments
 (0)