X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fpinctrl%2Fpinctrl-uclass.c;h=5b1cd29d862dc421405b90e3a691dea8a78c525b;hb=f681eacbfeb2598c135ef8e8ba8d5b9298a52a38;hp=29c910c55f3540982c4d182510d16b8555bb4064;hpb=a7f4b4b344396590845e6552c82829ef68ef9f89;p=oweals%2Fu-boot.git diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c index 29c910c55f..5b1cd29d86 100644 --- a/drivers/pinctrl/pinctrl-uclass.c +++ b/drivers/pinctrl/pinctrl-uclass.c @@ -116,10 +116,13 @@ static int pinconfig_post_bind(struct udevice *dev) ofnode node; int ret; + if (!dev_of_valid(dev)) + return 0; + dev_for_each_subnode(node, dev) { - if (pre_reloc_only ^ ofnode_pre_reloc(node)) + if (pre_reloc_only && + !ofnode_pre_reloc(node)) continue; - /* * If this node has "compatible" property, this is not * a pin configuration node, but a normal device. skip. @@ -127,6 +130,9 @@ static int pinconfig_post_bind(struct udevice *dev) ofnode_get_property(node, "compatible", &ret); if (ret >= 0) continue; + /* If this node has "gpio-controller" property, skip */ + if (ofnode_read_bool(node, "gpio-controller")) + continue; if (ret != -FDT_ERR_NOTFOUND) return ret; @@ -166,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 * @@ -179,11 +281,14 @@ static int pinctrl_select_state_simple(struct udevice *dev) int ret; /* - * For simplicity, assume the first device of PINCTRL uclass - * is the correct one. This is most likely OK as there is - * usually only one pinctrl device on the system. + * For most system, there is only one pincontroller device. But in + * case of multiple pincontroller devices, probe the one with sequence + * number 0 (defined by alias) to avoid race condition. */ - ret = uclass_get_device(UCLASS_PINCTRL, 0, &pctldev); + ret = uclass_get_device_by_seq(UCLASS_PINCTRL, 0, &pctldev); + if (ret) + /* if not found, get the first one */ + ret = uclass_get_device(UCLASS_PINCTRL, 0, &pctldev); if (ret) return ret;