[U-Boot] [PATCH 1/5] pinctrl: gpio: Add callback for configuring pin as GPIO

Add callback to configure, and de-configure, pin as a GPIO on the pin controller side. This matches similar functionality in Linux and aims to replace the ad-hoc implementations present in U-Boot.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Alex Kiernan alex.kiernan@gmail.com Cc: Christoph Muellner christoph.muellner@theobroma-systems.com Cc: Eugeniu Rosca roscaeugeniu@gmail.com Cc: Patrice Chotard patrice.chotard@st.com Cc: Patrick DELAUNAY patrick.delaunay@st.com Cc: Philipp Tomsich philipp.tomsich@theobroma-systems.com Cc: Simon Glass sjg@chromium.org --- drivers/pinctrl/pinctrl-uclass.c | 96 ++++++++++++++++++++++++++++++++ include/dm/pinctrl.h | 44 +++++++++++++++ 2 files changed, 140 insertions(+)
diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c index 0e6c559d5e..5f9672263f 100644 --- a/drivers/pinctrl/pinctrl-uclass.c +++ b/drivers/pinctrl/pinctrl-uclass.c @@ -169,6 +169,102 @@ static int pinconfig_post_bind(struct udevice *dev) } #endif
+static int +pinctrl_gpio_get_pinctrl_and_offset(struct udevice *dev, unsigned offset, + struct udevice **pctldev, + unsigned int *pin_selector) +{ + struct ofnode_phandle_args args; + unsigned gpio_offset, pfc_base, pfc_pins; + int ret; + + ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3, + 0, &args); + if (ret) { + dev_dbg(dev, "%s: dev_read_phandle_with_args: err=%d\n", + __func__, ret); + return ret; + } + + ret = uclass_get_device_by_ofnode(UCLASS_PINCTRL, + args.node, pctldev); + if (ret) { + dev_dbg(dev, + "%s: uclass_get_device_by_of_offset failed: err=%d\n", + __func__, ret); + return ret; + } + + gpio_offset = args.args[0]; + pfc_base = args.args[1]; + pfc_pins = args.args[2]; + + if (offset < gpio_offset || offset > gpio_offset + pfc_pins) { + dev_dbg(dev, + "%s: GPIO can not be mapped to pincontrol pin\n", + __func__); + return -EINVAL; + } + + offset -= gpio_offset; + offset += pfc_base; + *pin_selector = offset; + + return 0; +} + +/** + * pinctrl_gpio_request() - request a single pin to be used as GPIO + * + * @dev: GPIO peripheral device + * @offset: the GPIO pin offset from the GPIO controller + * @return: 0 on success, or negative error code on failure + */ +int pinctrl_gpio_request(struct udevice *dev, unsigned offset) +{ + const struct pinctrl_ops *ops; + struct udevice *pctldev; + unsigned int pin_selector; + int ret; + + ret = pinctrl_gpio_get_pinctrl_and_offset(dev, offset, + &pctldev, &pin_selector); + if (ret) + return ret; + + ops = pinctrl_get_ops(pctldev); + if (!ops || !ops->gpio_request_enable) + return -ENOTSUPP; + + return ops->gpio_request_enable(pctldev, pin_selector); +} + +/** + * pinctrl_gpio_free() - free a single pin used as GPIO + * + * @dev: GPIO peripheral device + * @offset: the GPIO pin offset from the GPIO controller + * @return: 0 on success, or negative error code on failure + */ +int pinctrl_gpio_free(struct udevice *dev, unsigned offset) +{ + const struct pinctrl_ops *ops; + struct udevice *pctldev; + unsigned int pin_selector; + int ret; + + ret = pinctrl_gpio_get_pinctrl_and_offset(dev, offset, + &pctldev, &pin_selector); + if (ret) + return ret; + + ops = pinctrl_get_ops(pctldev); + if (!ops || !ops->gpio_disable_free) + return -ENOTSUPP; + + return ops->gpio_disable_free(pctldev, pin_selector); +} + /** * pinctrl_select_state_simple() - simple implementation of pinctrl_select_state * diff --git a/include/dm/pinctrl.h b/include/dm/pinctrl.h index 63a7d55b88..e7b8ad9078 100644 --- a/include/dm/pinctrl.h +++ b/include/dm/pinctrl.h @@ -70,6 +70,13 @@ struct pinconf_param { * @set_state_simple: do needed pinctrl operations for a peripherl @periph. * (necessary for pinctrl_simple) * @get_pin_muxing: display the muxing of a given pin. + * @gpio_request_enable: requests and enables GPIO on a certain pin. + * Implement this only if you can mux every pin individually as GPIO. The + * affected GPIO range is passed along with an offset(pin number) into that + * specific GPIO range - function selectors and pin groups are orthogonal + * to this, the core will however make sure the pins do not collide. + * @gpio_disable_free: free up GPIO muxing on a certain pin, the reverse of + * @gpio_request_enable */ struct pinctrl_ops { int (*get_pins_count)(struct udevice *dev); @@ -151,6 +158,24 @@ struct pinctrl_ops { */ int (*get_pin_muxing)(struct udevice *dev, unsigned int selector, char *buf, int size); + + /** + * gpio_request_enable: requests and enables GPIO on a certain pin. + * + * @dev: Pinctrl device to use + * @selector: Pin selector + * return 0 if OK, -ve on error + */ + int (*gpio_request_enable)(struct udevice *dev, unsigned int selector); + + /** + * gpio_disable_free: free up GPIO muxing on a certain pin. + * + * @dev: Pinctrl device to use + * @selector: Pin selector + * return 0 if OK, -ve on error + */ + int (*gpio_disable_free)(struct udevice *dev, unsigned int selector); };
#define pinctrl_get_ops(dev) ((struct pinctrl_ops *)(dev)->driver->ops) @@ -407,4 +432,23 @@ int pinctrl_get_pins_count(struct udevice *dev); */ int pinctrl_get_pin_name(struct udevice *dev, int selector, char *buf, int size); + +/** + * pinctrl_gpio_request() - request a single pin to be used as GPIO + * + * @dev: GPIO peripheral device + * @offset: the GPIO pin offset from the GPIO controller + * @return: 0 on success, or negative error code on failure + */ +int pinctrl_gpio_request(struct udevice *dev, unsigned offset); + +/** + * pinctrl_gpio_free() - free a single pin used as GPIO + * + * @dev: GPIO peripheral device + * @offset: the GPIO pin offset from the GPIO controller + * @return: 0 on success, or negative error code on failure + */ +int pinctrl_gpio_free(struct udevice *dev, unsigned offset); + #endif /* __PINCTRL_H */

Add missing cfg->type = PINMUX_TYPE_GPIO upon successfully setting pin as a GPIO to retain the pin configuration information.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Alex Kiernan alex.kiernan@gmail.com Cc: Christoph Muellner christoph.muellner@theobroma-systems.com Cc: Eugeniu Rosca roscaeugeniu@gmail.com Cc: Patrice Chotard patrice.chotard@st.com Cc: Patrick DELAUNAY patrick.delaunay@st.com Cc: Philipp Tomsich philipp.tomsich@theobroma-systems.com Cc: Simon Glass sjg@chromium.org --- drivers/pinctrl/renesas/pfc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/pinctrl/renesas/pfc.c b/drivers/pinctrl/renesas/pfc.c index 06359501b7..59dc4af702 100644 --- a/drivers/pinctrl/renesas/pfc.c +++ b/drivers/pinctrl/renesas/pfc.c @@ -466,7 +466,7 @@ int sh_pfc_config_mux_for_gpio(struct udevice *dev, unsigned pin_selector) struct sh_pfc *pfc = &priv->pfc; struct sh_pfc_pin_config *cfg; const struct sh_pfc_pin *pin = NULL; - int i, idx; + int i, ret, idx;
for (i = 1; i < pfc->info->nr_pins; i++) { if (priv->pfc.info->pins[i].pin != pin_selector) @@ -485,7 +485,13 @@ int sh_pfc_config_mux_for_gpio(struct udevice *dev, unsigned pin_selector) if (cfg->type != PINMUX_TYPE_NONE) return -EBUSY;
- return sh_pfc_config_mux(pfc, pin->enum_id, PINMUX_TYPE_GPIO); + ret = sh_pfc_config_mux(pfc, pin->enum_id, PINMUX_TYPE_GPIO); + if (ret) + return ret; + + cfg->type = PINMUX_TYPE_GPIO; + + return 0; }
static int sh_pfc_pinctrl_pin_set(struct udevice *dev, unsigned pin_selector,

On Mon, Apr 22, 2019 at 12:20 AM Marek Vasut marek.vasut@gmail.com wrote:
Add missing cfg->type = PINMUX_TYPE_GPIO upon successfully setting pin as a GPIO to retain the pin configuration information.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com
Fixes: f6e545a73f8842 ("pfc: rmobile: Add hook to configure pin as GPIO") Reviewed-by: Eugeniu Rosca erosca@de.adit-jv.com Tested-by: Eugeniu Rosca erosca@de.adit-jv.com

Implement the gpio_request_enable/gpio_disable_free callbacks to let the GPIO driver call the pin control framework and let it reconfigure pins as GPIOs.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Alex Kiernan alex.kiernan@gmail.com Cc: Christoph Muellner christoph.muellner@theobroma-systems.com Cc: Eugeniu Rosca roscaeugeniu@gmail.com Cc: Patrice Chotard patrice.chotard@st.com Cc: Patrick DELAUNAY patrick.delaunay@st.com Cc: Philipp Tomsich philipp.tomsich@theobroma-systems.com Cc: Simon Glass sjg@chromium.org --- drivers/pinctrl/renesas/pfc.c | 40 ++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-)
diff --git a/drivers/pinctrl/renesas/pfc.c b/drivers/pinctrl/renesas/pfc.c index 59dc4af702..52c486ebc2 100644 --- a/drivers/pinctrl/renesas/pfc.c +++ b/drivers/pinctrl/renesas/pfc.c @@ -459,7 +459,8 @@ static const char *sh_pfc_pinctrl_get_function_name(struct udevice *dev, return priv->pfc.info->functions[selector].name; }
-int sh_pfc_config_mux_for_gpio(struct udevice *dev, unsigned pin_selector) +static int sh_pfc_gpio_request_enable(struct udevice *dev, + unsigned pin_selector) { struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev); struct sh_pfc_pinctrl *pmx = &priv->pmx; @@ -494,6 +495,40 @@ int sh_pfc_config_mux_for_gpio(struct udevice *dev, unsigned pin_selector) return 0; }
+static int sh_pfc_gpio_disable_free(struct udevice *dev, + unsigned pin_selector) +{ + struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev); + struct sh_pfc_pinctrl *pmx = &priv->pmx; + struct sh_pfc *pfc = &priv->pfc; + struct sh_pfc_pin_config *cfg; + const struct sh_pfc_pin *pin = NULL; + int i, idx; + + for (i = 1; i < pfc->info->nr_pins; i++) { + if (priv->pfc.info->pins[i].pin != pin_selector) + continue; + + pin = &priv->pfc.info->pins[i]; + break; + } + + if (!pin) + return -EINVAL; + + idx = sh_pfc_get_pin_index(pfc, pin->pin); + cfg = &pmx->configs[idx]; + + cfg->type = PINMUX_TYPE_NONE; + + return 0; +} + +int sh_pfc_config_mux_for_gpio(struct udevice *dev, unsigned pin_selector) +{ + return sh_pfc_gpio_request_enable(dev, pin_selector); +} + static int sh_pfc_pinctrl_pin_set(struct udevice *dev, unsigned pin_selector, unsigned func_selector) { @@ -752,6 +787,9 @@ static struct pinctrl_ops sh_pfc_pinctrl_ops = { .pinmux_set = sh_pfc_pinctrl_pin_set, .pinmux_group_set = sh_pfc_pinctrl_group_set, .set_state = pinctrl_generic_set_state, + + .gpio_request_enable = sh_pfc_gpio_request_enable, + .gpio_disable_free = sh_pfc_gpio_disable_free, };
static int sh_pfc_map_pins(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx)

On Mon, Apr 22, 2019 at 12:20 AM Marek Vasut marek.vasut@gmail.com wrote: [..]
-int sh_pfc_config_mux_for_gpio(struct udevice *dev, unsigned pin_selector) +static int sh_pfc_gpio_request_enable(struct udevice *dev,
unsigned pin_selector)
FTR, checkpatch is not happy about bare usage of 'unsigned'. It seems to be a global issue in U-Boot.
Reviewed-by: Eugeniu Rosca erosca@de.adit-jv.com Tested-by: Eugeniu Rosca erosca@de.adit-jv.com

Switch to generic pin controller API for configuring pins as GPIOs instead of using the ad-hoc call into the R-Car PFC driver. Moreover, add .free() implementation for the GPIO controller.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Alex Kiernan alex.kiernan@gmail.com Cc: Christoph Muellner christoph.muellner@theobroma-systems.com Cc: Eugeniu Rosca roscaeugeniu@gmail.com Cc: Patrice Chotard patrice.chotard@st.com Cc: Patrick DELAUNAY patrick.delaunay@st.com Cc: Philipp Tomsich philipp.tomsich@theobroma-systems.com Cc: Simon Glass sjg@chromium.org --- drivers/gpio/gpio-rcar.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 6fd1270640..594e0a470a 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -6,6 +6,7 @@ #include <common.h> #include <clk.h> #include <dm.h> +#include <dm/pinctrl.h> #include <errno.h> #include <asm/gpio.h> #include <asm/io.h> @@ -117,19 +118,17 @@ static int rcar_gpio_get_function(struct udevice *dev, unsigned offset) static int rcar_gpio_request(struct udevice *dev, unsigned offset, const char *label) { - struct rcar_gpio_priv *priv = dev_get_priv(dev); - struct udevice *pctldev; - int ret; - - ret = uclass_get_device(UCLASS_PINCTRL, 0, &pctldev); - if (ret) - return ret; + return pinctrl_gpio_request(dev, offset); +}
- return sh_pfc_config_mux_for_gpio(pctldev, priv->pfc_offset + offset); +static int rcar_gpio_free(struct udevice *dev, unsigned offset) +{ + return pinctrl_gpio_free(dev, offset); }
static const struct dm_gpio_ops rcar_gpio_ops = { .request = rcar_gpio_request, + .free = rcar_gpio_free, .direction_input = rcar_gpio_direction_input, .direction_output = rcar_gpio_direction_output, .get_value = rcar_gpio_get_value,

On Mon, Apr 22, 2019 at 12:20 AM Marek Vasut marek.vasut@gmail.com wrote:
Switch to generic pin controller API for configuring pins as GPIOs instead of using the ad-hoc call into the R-Car PFC driver. Moreover, add .free() implementation for the GPIO controller.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com
Reviewed-by: Eugeniu Rosca erosca@de.adit-jv.com Tested-by: Eugeniu Rosca erosca@de.adit-jv.com

This function is now replaced by common pin controller GPIO configuration functionality, drop it.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Alex Kiernan alex.kiernan@gmail.com Cc: Christoph Muellner christoph.muellner@theobroma-systems.com Cc: Eugeniu Rosca roscaeugeniu@gmail.com Cc: Patrice Chotard patrice.chotard@st.com Cc: Patrick DELAUNAY patrick.delaunay@st.com Cc: Philipp Tomsich philipp.tomsich@theobroma-systems.com Cc: Simon Glass sjg@chromium.org --- drivers/pinctrl/renesas/pfc.c | 5 ----- drivers/pinctrl/renesas/sh_pfc.h | 1 - 2 files changed, 6 deletions(-)
diff --git a/drivers/pinctrl/renesas/pfc.c b/drivers/pinctrl/renesas/pfc.c index 52c486ebc2..d1271dad44 100644 --- a/drivers/pinctrl/renesas/pfc.c +++ b/drivers/pinctrl/renesas/pfc.c @@ -524,11 +524,6 @@ static int sh_pfc_gpio_disable_free(struct udevice *dev, return 0; }
-int sh_pfc_config_mux_for_gpio(struct udevice *dev, unsigned pin_selector) -{ - return sh_pfc_gpio_request_enable(dev, pin_selector); -} - static int sh_pfc_pinctrl_pin_set(struct udevice *dev, unsigned pin_selector, unsigned func_selector) { diff --git a/drivers/pinctrl/renesas/sh_pfc.h b/drivers/pinctrl/renesas/sh_pfc.h index 09e11d31b3..6629e1f772 100644 --- a/drivers/pinctrl/renesas/sh_pfc.h +++ b/drivers/pinctrl/renesas/sh_pfc.h @@ -275,7 +275,6 @@ void sh_pfc_write(struct sh_pfc *pfc, u32 reg, u32 data); const struct pinmux_bias_reg * sh_pfc_pin_to_bias_reg(const struct sh_pfc *pfc, unsigned int pin, unsigned int *bit); -int sh_pfc_config_mux_for_gpio(struct udevice *dev, unsigned pin_selector);
extern const struct sh_pfc_soc_info r8a7790_pinmux_info; extern const struct sh_pfc_soc_info r8a7791_pinmux_info;

On Mon, Apr 22, 2019 at 12:20 AM Marek Vasut marek.vasut@gmail.com wrote:
This function is now replaced by common pin controller GPIO configuration functionality, drop it.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com
Reviewed-by: Eugeniu Rosca erosca@de.adit-jv.com
Thanks!

On Mon, Apr 22, 2019 at 12:20 AM Marek Vasut marek.vasut@gmail.com wrote:
[..]
- @gpio_request_enable: requests and enables GPIO on a certain pin.
nit: the existing documentation follows an imperative mood
[..]
* gpio_request_enable: requests and enables GPIO on a certain pin.
[..]
* gpio_disable_free: free up GPIO muxing on a certain pin.
nit: the established pattern is: 'name() - description', while here I see 'name: description.'
Other than that: Reviewed-by: Eugeniu Rosca erosca@de.adit-jv.com Tested-by: Eugeniu Rosca erosca@de.adit-jv.com
Thanks!

On 4/26/19 2:16 PM, Eugeniu Rosca wrote:
On Mon, Apr 22, 2019 at 12:20 AM Marek Vasut marek.vasut@gmail.com wrote:
[..]
- @gpio_request_enable: requests and enables GPIO on a certain pin.
nit: the existing documentation follows an imperative mood
[..]
* gpio_request_enable: requests and enables GPIO on a certain pin.
[..]
* gpio_disable_free: free up GPIO muxing on a certain pin.
nit: the established pattern is: 'name() - description', while here I see 'name: description.'
Other than that: Reviewed-by: Eugeniu Rosca erosca@de.adit-jv.com Tested-by: Eugeniu Rosca erosca@de.adit-jv.com
Thanks!
I copied the documentation from Linux, so I'll keep it as-is.
participants (2)
-
Eugeniu Rosca
-
Marek Vasut