diff options
-rw-r--r-- | drivers/pinctrl/pinctrl-single.c | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index cf9ad3670f..0f96cd5870 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -8,6 +8,7 @@ #include <dm.h> #include <dm/device_compat.h> #include <dm/devres.h> +#include <dm/of_access.h> #include <dm/pinctrl.h> #include <linux/libfdt.h> #include <linux/list.h> @@ -45,10 +46,26 @@ struct single_func { }; /** + * struct single_gpiofunc_range - pin ranges with same mux value of gpio fun + * @offset: offset base of pins + * @npins: number pins with the same mux value of gpio function + * @gpiofunc: mux value of gpio function + * @node: list node + */ +struct single_gpiofunc_range { + u32 offset; + u32 npins; + u32 gpiofunc; + struct list_head node; +}; + +/** * struct single_priv - private data * @bits_per_pin: number of bits per pin * @npins: number of selectable pins * @pin_name: temporary buffer to store the pin name + * @functions: list pin functions + * @gpiofuncs: list gpio functions */ struct single_priv { #if (IS_ENABLED(CONFIG_SANDBOX)) @@ -58,6 +75,7 @@ struct single_priv { unsigned int npins; char pin_name[PINNAME_SIZE]; struct list_head functions; + struct list_head gpiofuncs; }; /** @@ -454,6 +472,36 @@ static int single_get_pins_count(struct udevice *dev) return priv->npins; } +static int single_add_gpio_func(struct udevice *dev) +{ + struct single_priv *priv = dev_get_priv(dev); + const char *propname = "pinctrl-single,gpio-range"; + const char *cellname = "#pinctrl-single,gpio-range-cells"; + struct single_gpiofunc_range *range; + struct ofnode_phandle_args gpiospec; + int ret, i; + + for (i = 0; ; i++) { + ret = ofnode_parse_phandle_with_args(dev_ofnode(dev), propname, + cellname, 0, i, &gpiospec); + /* Do not treat it as error. Only treat it as end condition. */ + if (ret) { + ret = 0; + break; + } + range = devm_kzalloc(dev, sizeof(*range), GFP_KERNEL); + if (!range) { + ret = -ENOMEM; + break; + } + range->offset = gpiospec.args[0]; + range->npins = gpiospec.args[1]; + range->gpiofunc = gpiospec.args[2]; + list_add_tail(&range->node, &priv->gpiofuncs); + } + return ret; +} + static int single_probe(struct udevice *dev) { struct single_pdata *pdata = dev_get_plat(dev); @@ -461,6 +509,7 @@ static int single_probe(struct udevice *dev) u32 size; INIT_LIST_HEAD(&priv->functions); + INIT_LIST_HEAD(&priv->gpiofuncs); size = pdata->offset + pdata->width / BITS_PER_BYTE; #if (CONFIG_IS_ENABLED(SANDBOX)) @@ -483,6 +532,9 @@ static int single_probe(struct udevice *dev) priv->npins *= (pdata->width / priv->bits_per_pin); } + if (single_add_gpio_func(dev)) + dev_dbg(dev, "gpio functions are not added\n"); + dev_dbg(dev, "%d pins\n", priv->npins); return 0; } |