summaryrefslogtreecommitdiff
path: root/drivers/pinctrl/bcm/pinctrl-bcm2835.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pinctrl/bcm/pinctrl-bcm2835.c')
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm2835.c19
1 files changed, 15 insertions, 4 deletions
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
index f5a9372d43bd..7178a38475cc 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
@@ -244,6 +244,10 @@ static const char * const irq_type_names[] = {
[IRQ_TYPE_LEVEL_LOW] = "level-low",
};
+static bool persist_gpio_outputs;
+module_param(persist_gpio_outputs, bool, 0644);
+MODULE_PARM_DESC(persist_gpio_outputs, "Enable GPIO_OUT persistence when pin is freed");
+
static inline u32 bcm2835_gpio_rd(struct bcm2835_pinctrl *pc, unsigned reg)
{
return readl(pc->base + reg);
@@ -926,6 +930,13 @@ static int bcm2835_pmx_free(struct pinctrl_dev *pctldev,
unsigned offset)
{
struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
+ enum bcm2835_fsel fsel = bcm2835_pinctrl_fsel_get(pc, offset);
+
+ if (fsel == BCM2835_FSEL_GPIO_IN)
+ return 0;
+
+ if (persist_gpio_outputs && fsel == BCM2835_FSEL_GPIO_OUT)
+ return 0;
/* disable by setting to GPIO_IN */
bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_IN);
@@ -970,10 +981,7 @@ static void bcm2835_pmx_gpio_disable_free(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset)
{
- struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
-
- /* disable by setting to GPIO_IN */
- bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_IN);
+ bcm2835_pmx_free(pctldev, offset);
}
static int bcm2835_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
@@ -1419,6 +1427,9 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
goto out_remove;
}
+ dev_info(dev, "GPIO_OUT persistence: %s\n",
+ persist_gpio_outputs ? "yes" : "no");
+
return 0;
out_remove: