From ae59d7ca59dbfc770531f51c717dc6f5d9a18f78 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 21 Apr 2019 23:57:23 +0200 Subject: [PATCH] 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 Cc: Alex Kiernan Cc: Christoph Muellner Cc: Eugeniu Rosca Cc: Patrice Chotard Cc: Patrick DELAUNAY Cc: Philipp Tomsich Cc: Simon Glass --- 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 f01bc77a57..5b1cd29d86 100644 --- a/drivers/pinctrl/pinctrl-uclass.c +++ b/drivers/pinctrl/pinctrl-uclass.c @@ -172,6 +172,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 */ -- 2.25.1