1 From 19b18f44e438ed1322718067b4feff30691f201f Mon Sep 17 00:00:00 2001
2 From: Stefan Wahren <wahrenst@gmx.net>
3 Date: Fri, 3 May 2024 08:27:45 +0200
4 Subject: [PATCH 1080/1085] pinctrl: bcm2835: Make pin freeing behavior
7 commit 8ff05989b44e1a8f7d2bbe67320990ebc2fbb5e5 upstream.
9 Until now after a bcm2835 pin was freed its pinmux was set to GPIO_IN.
10 So in case it was configured as GPIO_OUT before the configured output
11 level also get lost. As long as GPIO sysfs was used this wasn't
12 actually a problem because the pins and their possible output level
15 Since more and more Raspberry Pi users start using libgpiod they are
16 confused about this behavior. So make the pin freeing behavior of
17 GPIO_OUT configurable via module parameter. In case
18 pinctrl-bcm2835.persist_gpio_outputs is set to 1, the output level is
21 This patch based on the downstream work of Phil Elwell.
23 Link: https://github.com/raspberrypi/linux/pull/6117
24 Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
25 Message-ID: <20240503062745.11298-1-wahrenst@gmx.net>
26 Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
28 drivers/pinctrl/bcm/pinctrl-bcm2835.c | 19 +++++++++++++++----
29 1 file changed, 15 insertions(+), 4 deletions(-)
31 --- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
32 +++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
33 @@ -244,6 +244,10 @@ static const char * const irq_type_names
34 [IRQ_TYPE_LEVEL_LOW] = "level-low",
37 +static bool persist_gpio_outputs;
38 +module_param(persist_gpio_outputs, bool, 0644);
39 +MODULE_PARM_DESC(persist_gpio_outputs, "Enable GPIO_OUT persistence when pin is freed");
41 static inline u32 bcm2835_gpio_rd(struct bcm2835_pinctrl *pc, unsigned reg)
43 return readl(pc->base + reg);
44 @@ -939,6 +943,13 @@ static int bcm2835_pmx_free(struct pinct
47 struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
48 + enum bcm2835_fsel fsel = bcm2835_pinctrl_fsel_get(pc, offset);
50 + if (fsel == BCM2835_FSEL_GPIO_IN)
53 + if (persist_gpio_outputs && fsel == BCM2835_FSEL_GPIO_OUT)
56 /* disable by setting to GPIO_IN */
57 bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_IN);
58 @@ -983,10 +994,7 @@ static void bcm2835_pmx_gpio_disable_fre
59 struct pinctrl_gpio_range *range,
62 - struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
64 - /* disable by setting to GPIO_IN */
65 - bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_IN);
66 + bcm2835_pmx_free(pctldev, offset);
69 static int bcm2835_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
70 @@ -1374,6 +1382,9 @@ static int bcm2835_pinctrl_probe(struct
74 + dev_info(dev, "GPIO_OUT persistence: %s\n",
75 + persist_gpio_outputs ? "yes" : "no");