Skip to content

Commit 19b18f4

Browse files
lategoodbyepelwell
authored andcommitted
pinctrl: bcm2835: Make pin freeing behavior configurable
commit 8ff0598 upstream. Until now after a bcm2835 pin was freed its pinmux was set to GPIO_IN. So in case it was configured as GPIO_OUT before the configured output level also get lost. As long as GPIO sysfs was used this wasn't actually a problem because the pins and their possible output level were kept by sysfs. Since more and more Raspberry Pi users start using libgpiod they are confused about this behavior. So make the pin freeing behavior of GPIO_OUT configurable via module parameter. In case pinctrl-bcm2835.persist_gpio_outputs is set to 1, the output level is kept. This patch based on the downstream work of Phil Elwell. Link: #6117 Signed-off-by: Stefan Wahren <wahrenst@gmx.net> Message-ID: <20240503062745.11298-1-wahrenst@gmx.net> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
1 parent b35d478 commit 19b18f4

File tree

1 file changed

+15
-4
lines changed

1 file changed

+15
-4
lines changed

drivers/pinctrl/bcm/pinctrl-bcm2835.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,10 @@ static const char * const irq_type_names[] = {
244244
[IRQ_TYPE_LEVEL_LOW] = "level-low",
245245
};
246246

247+
static bool persist_gpio_outputs;
248+
module_param(persist_gpio_outputs, bool, 0644);
249+
MODULE_PARM_DESC(persist_gpio_outputs, "Enable GPIO_OUT persistence when pin is freed");
250+
247251
static inline u32 bcm2835_gpio_rd(struct bcm2835_pinctrl *pc, unsigned reg)
248252
{
249253
return readl(pc->base + reg);
@@ -939,6 +943,13 @@ static int bcm2835_pmx_free(struct pinctrl_dev *pctldev,
939943
unsigned offset)
940944
{
941945
struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
946+
enum bcm2835_fsel fsel = bcm2835_pinctrl_fsel_get(pc, offset);
947+
948+
if (fsel == BCM2835_FSEL_GPIO_IN)
949+
return 0;
950+
951+
if (persist_gpio_outputs && fsel == BCM2835_FSEL_GPIO_OUT)
952+
return 0;
942953

943954
/* disable by setting to GPIO_IN */
944955
bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_IN);
@@ -983,10 +994,7 @@ static void bcm2835_pmx_gpio_disable_free(struct pinctrl_dev *pctldev,
983994
struct pinctrl_gpio_range *range,
984995
unsigned offset)
985996
{
986-
struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
987-
988-
/* disable by setting to GPIO_IN */
989-
bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_IN);
997+
bcm2835_pmx_free(pctldev, offset);
990998
}
991999

9921000
static int bcm2835_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
@@ -1374,6 +1382,9 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
13741382
goto out_remove;
13751383
}
13761384

1385+
dev_info(dev, "GPIO_OUT persistence: %s\n",
1386+
persist_gpio_outputs ? "yes" : "no");
1387+
13771388
return 0;
13781389

13791390
out_remove:

0 commit comments

Comments
 (0)