From 12ef9a4189cd44212a5a5bd2e1c6fce0756ace9f Mon Sep 17 00:00:00 2001 From: "Jason M. Bills" Date: Fri, 3 May 2019 16:12:39 -0700 Subject: [PATCH] Enable pass-through on GPIOE1 and GPIOE3 free This change adds a gpio_disable_free() implementation that checks if the GPIO being freed is GPIOE1 (33) or GPIOE3 (35) and will re-enable the pass-through mux. Tested: Requested GPIOs 33 and 35 and used devmem to check that pass-through was disabled. Then freed them and checked that pass-through was enabled again. Signed-off-by: Jason M. Bills --- drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 17 ++++++++++ drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c | 17 ++++++++++ drivers/pinctrl/aspeed/pinctrl-aspeed.c | 53 ++++++++++++++++++++++++++++++ drivers/pinctrl/aspeed/pinctrl-aspeed.h | 3 ++ 4 files changed, 90 insertions(+) diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c index 0cab4c2576e2..c5406e2da320 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c @@ -2780,6 +2780,22 @@ static int aspeed_g5_sig_expr_set(struct aspeed_pinmux_data *ctx, return 0; } +#define GPIOE1 33 +#define GPIOE3 35 +static void aspeed_g5_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + /* + * If we're freeing GPIOE1 (33) or GPIOE3 (35) then re-enable the + * pass-through mux setting; otherwise, do nothing. + */ + if (offset != GPIOE1 && offset != GPIOE3) + return; + + aspeed_gpio_disable_free(pctldev, range, offset); +} + static const struct aspeed_pin_config_map aspeed_g5_pin_config_map[] = { { PIN_CONFIG_BIAS_PULL_DOWN, 0, 1, BIT_MASK(0)}, { PIN_CONFIG_BIAS_PULL_DOWN, -1, 0, BIT_MASK(0)}, @@ -2815,6 +2831,7 @@ static const struct pinmux_ops aspeed_g5_pinmux_ops = { .get_function_groups = aspeed_pinmux_get_fn_groups, .set_mux = aspeed_pinmux_set_mux, .gpio_request_enable = aspeed_gpio_request_enable, + .gpio_disable_free = aspeed_g5_gpio_disable_free, .strict = true, }; diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c index fb96e8d2e6c8..bcd8c5656265 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c @@ -2655,6 +2655,22 @@ static int aspeed_g6_sig_expr_set(struct aspeed_pinmux_data *ctx, return 0; } +#define GPIOP1 121 +#define GPIOP3 123 +static void aspeed_g6_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + /* + * If we're freeing GPIOP1 (121) or GPIOP3 (123) then re-enable the + * pass-through mux setting; otherwise, do nothing. + */ + if (offset != GPIOP1 && offset != GPIOP3) + return; + + aspeed_gpio_disable_free(pctldev, range, offset); +} + static const struct aspeed_pin_config_map aspeed_g6_pin_config_map[] = { { PIN_CONFIG_BIAS_PULL_DOWN, 0, 1, BIT_MASK(0)}, { PIN_CONFIG_BIAS_PULL_DOWN, -1, 0, BIT_MASK(0)}, @@ -2695,6 +2711,7 @@ static const struct pinmux_ops aspeed_g6_pinmux_ops = { .get_function_groups = aspeed_pinmux_get_fn_groups, .set_mux = aspeed_pinmux_set_mux, .gpio_request_enable = aspeed_gpio_request_enable, + .gpio_disable_free = aspeed_g6_gpio_disable_free, .strict = true, }; diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.c b/drivers/pinctrl/aspeed/pinctrl-aspeed.c index 53f3f8aec695..ca53f3743d16 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.c @@ -375,6 +375,59 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev, return 0; } +void aspeed_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + const struct aspeed_pin_desc *pdesc = pdata->pins[offset].drv_data; + const struct aspeed_sig_expr ***prios, **funcs, *expr; + int ret; + + if (!pdesc) + return; + + dev_dbg(pctldev->dev, + "Freeing pass-through pin %s (%d). Re-enabling pass-through.\n", + pdesc->name, offset); + + prios = pdesc->prios; + + if (!prios) + return; + + /* Disable any functions of higher priority than GPIO just in case */ + while ((funcs = *prios)) { + if (aspeed_gpio_in_exprs(funcs)) + break; + + ret = aspeed_disable_sig(&pdata->pinmux, funcs); + if (ret) + return; + + prios++; + } + + if (!funcs) { + char *signals = get_defined_signals(pdesc); + + pr_warn("No GPIO signal type found on pin %s (%d). Found: %s\n", + pdesc->name, offset, signals); + kfree(signals); + + return; + } + + /* + * Pass-through should be one priority higher than the GPIO function, + * so decrement our prios and enable that function + */ + prios--; + funcs = *prios; + expr = *funcs; + aspeed_sig_expr_enable(&pdata->pinmux, expr); +} + int aspeed_pinctrl_probe(struct platform_device *pdev, struct pinctrl_desc *pdesc, struct aspeed_pinctrl_data *pdata) diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.h b/drivers/pinctrl/aspeed/pinctrl-aspeed.h index 4dcde3bc29c8..bd497c20a15f 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed.h +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.h @@ -101,6 +101,9 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned int offset); +void aspeed_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset); int aspeed_pinctrl_probe(struct platform_device *pdev, struct pinctrl_desc *pdesc, struct aspeed_pinctrl_data *pdata); -- 2.7.4