diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/core/of_access.c | 32 | ||||
-rw-r--r-- | drivers/core/ofnode.c | 48 | ||||
-rw-r--r-- | drivers/core/read.c | 16 | ||||
-rw-r--r-- | drivers/gpio/gpio-uclass.c | 204 | ||||
-rw-r--r-- | drivers/gpio/mpc8xxx_gpio.c | 22 | ||||
-rw-r--r-- | drivers/gpio/sandbox.c | 322 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-generic.c | 30 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-sandbox.c | 44 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-single.c | 27 |
9 files changed, 574 insertions, 171 deletions
diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c index c54baa140a..ea3ee8bd63 100644 --- a/drivers/core/of_access.c +++ b/drivers/core/of_access.c @@ -171,6 +171,38 @@ const void *of_get_property(const struct device_node *np, const char *name, return pp ? pp->value : NULL; } +const struct property *of_get_first_property(const struct device_node *np) +{ + if (!np) + return NULL; + + return np->properties; +} + +const struct property *of_get_next_property(const struct device_node *np, + const struct property *property) +{ + if (!np) + return NULL; + + return property->next; +} + +const void *of_get_property_by_prop(const struct device_node *np, + const struct property *property, + const char **name, + int *lenp) +{ + if (!np || !property) + return NULL; + if (name) + *name = property->name; + if (lenp) + *lenp = property->length; + + return property->value; +} + static const char *of_prop_next_string(struct property *prop, const char *cur) { const void *curv = cur; diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index b0be7cbe19..20871a6815 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -571,6 +571,54 @@ const void *ofnode_get_property(ofnode node, const char *propname, int *lenp) propname, lenp); } +int ofnode_get_first_property(ofnode node, struct ofprop *prop) +{ + prop->node = node; + + if (ofnode_is_np(node)) { + prop->prop = of_get_first_property(ofnode_to_np(prop->node)); + if (!prop->prop) + return -FDT_ERR_NOTFOUND; + } else { + prop->offset = + fdt_first_property_offset(gd->fdt_blob, + ofnode_to_offset(prop->node)); + if (prop->offset < 0) + return prop->offset; + } + + return 0; +} + +int ofnode_get_next_property(struct ofprop *prop) +{ + if (ofnode_is_np(prop->node)) { + prop->prop = of_get_next_property(ofnode_to_np(prop->node), + prop->prop); + if (!prop->prop) + return -FDT_ERR_NOTFOUND; + } else { + prop->offset = fdt_next_property_offset(gd->fdt_blob, + prop->offset); + if (prop->offset < 0) + return prop->offset; + } + + return 0; +} + +const void *ofnode_get_property_by_prop(const struct ofprop *prop, + const char **propname, int *lenp) +{ + if (ofnode_is_np(prop->node)) + return of_get_property_by_prop(ofnode_to_np(prop->node), + prop->prop, propname, lenp); + else + return fdt_getprop_by_offset(gd->fdt_blob, + prop->offset, + propname, lenp); +} + bool ofnode_is_available(ofnode node) { if (ofnode_is_np(node)) diff --git a/drivers/core/read.c b/drivers/core/read.c index ce78f09d28..47b8e03446 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -255,6 +255,22 @@ const void *dev_read_prop(const struct udevice *dev, const char *propname, return ofnode_get_property(dev_ofnode(dev), propname, lenp); } +int dev_read_first_prop(const struct udevice *dev, struct ofprop *prop) +{ + return ofnode_get_first_property(dev_ofnode(dev), prop); +} + +int dev_read_next_prop(struct ofprop *prop) +{ + return ofnode_get_next_property(prop); +} + +const void *dev_read_prop_by_prop(struct ofprop *prop, + const char **propname, int *lenp) +{ + return ofnode_get_property_by_prop(prop, propname, lenp); +} + int dev_read_alias_seq(const struct udevice *dev, int *devnump) { ofnode node = dev_ofnode(dev); diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 0a22441d38..757ab7106e 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -5,6 +5,7 @@ #include <common.h> #include <dm.h> +#include <dm/device_compat.h> #include <dm/device-internal.h> #include <dm/lists.h> #include <dm/uclass-internal.h> @@ -19,6 +20,22 @@ DECLARE_GLOBAL_DATA_PTR; /** + * gpio_desc_init() - Initialize the GPIO descriptor + * + * @desc: GPIO descriptor to initialize + * @dev: GPIO device + * @offset: Offset of device GPIO + */ +static void gpio_desc_init(struct gpio_desc *desc, + struct udevice *dev, + uint offset) +{ + desc->dev = dev; + desc->offset = offset; + desc->flags = 0; +} + +/** * gpio_to_device() - Convert global GPIO number to device, number * * Convert the GPIO number to an entry in the list of GPIOs @@ -41,9 +58,7 @@ static int gpio_to_device(unsigned int gpio, struct gpio_desc *desc) uc_priv = dev_get_uclass_priv(dev); if (gpio >= uc_priv->gpio_base && gpio < uc_priv->gpio_base + uc_priv->gpio_count) { - desc->dev = dev; - desc->offset = gpio - uc_priv->gpio_base; - desc->flags = 0; + gpio_desc_init(desc, dev, gpio - uc_priv->gpio_base); return 0; } } @@ -85,8 +100,7 @@ int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc) if (!dev) return ret ? ret : -EINVAL; - desc->dev = dev; - desc->offset = offset; + gpio_desc_init(desc, dev, offset); return 0; } @@ -127,8 +141,27 @@ int gpio_xlate_offs_flags(struct udevice *dev, struct gpio_desc *desc, if (args->args_count < 2) return 0; + desc->flags = 0; if (args->args[1] & GPIO_ACTIVE_LOW) - desc->flags = GPIOD_ACTIVE_LOW; + desc->flags |= GPIOD_ACTIVE_LOW; + + /* + * need to test 2 bits for gpio output binding: + * OPEN_DRAIN (0x6) = SINGLE_ENDED (0x2) | LINE_OPEN_DRAIN (0x4) + * OPEN_SOURCE (0x2) = SINGLE_ENDED (0x2) | LINE_OPEN_SOURCE (0x0) + */ + if (args->args[1] & GPIO_SINGLE_ENDED) { + if (args->args[1] & GPIO_LINE_OPEN_DRAIN) + desc->flags |= GPIOD_OPEN_DRAIN; + else + desc->flags |= GPIOD_OPEN_SOURCE; + } + + if (args->args[1] & GPIO_PULL_UP) + desc->flags |= GPIOD_PULL_UP; + + if (args->args[1] & GPIO_PULL_DOWN) + desc->flags |= GPIOD_PULL_DOWN; return 0; } @@ -463,18 +496,24 @@ int gpio_direction_output(unsigned gpio, int value) desc.offset, value); } -int dm_gpio_get_value(const struct gpio_desc *desc) +static int _gpio_get_value(const struct gpio_desc *desc) { int value; + + value = gpio_get_ops(desc->dev)->get_value(desc->dev, desc->offset); + + return desc->flags & GPIOD_ACTIVE_LOW ? !value : value; +} + +int dm_gpio_get_value(const struct gpio_desc *desc) +{ int ret; ret = check_reserved(desc, "get_value"); if (ret) return ret; - value = gpio_get_ops(desc->dev)->get_value(desc->dev, desc->offset); - - return desc->flags & GPIOD_ACTIVE_LOW ? !value : value; + return _gpio_get_value(desc); } int dm_gpio_set_value(const struct gpio_desc *desc, int value) @@ -491,71 +530,128 @@ int dm_gpio_set_value(const struct gpio_desc *desc, int value) return 0; } -int dm_gpio_get_open_drain(struct gpio_desc *desc) +/* check dir flags invalid configuration */ +static int check_dir_flags(ulong flags) { - struct dm_gpio_ops *ops = gpio_get_ops(desc->dev); - int ret; + if ((flags & GPIOD_IS_OUT) && (flags & GPIOD_IS_IN)) { + log_debug("%s: flags 0x%lx has GPIOD_IS_OUT and GPIOD_IS_IN\n", + __func__, flags); + return -EINVAL; + } + + if ((flags & GPIOD_PULL_UP) && (flags & GPIOD_PULL_DOWN)) { + log_debug("%s: flags 0x%lx has GPIOD_PULL_UP and GPIOD_PULL_DOWN\n", + __func__, flags); + return -EINVAL; + } + + if ((flags & GPIOD_OPEN_DRAIN) && (flags & GPIOD_OPEN_SOURCE)) { + log_debug("%s: flags 0x%lx has GPIOD_OPEN_DRAIN and GPIOD_OPEN_SOURCE\n", + __func__, flags); + return -EINVAL; + } + + return 0; +} + +static int _dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags) +{ + struct udevice *dev = desc->dev; + struct dm_gpio_ops *ops = gpio_get_ops(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + int ret = 0; + + ret = check_dir_flags(flags); + if (ret) { + dev_dbg(dev, + "%s error: set_dir_flags for gpio %s%d has invalid dir flags 0x%lx\n", + desc->dev->name, + uc_priv->bank_name ? uc_priv->bank_name : "", + desc->offset, flags); - ret = check_reserved(desc, "get_open_drain"); - if (ret) return ret; + } - if (ops->set_open_drain) - return ops->get_open_drain(desc->dev, desc->offset); - else - return -ENOSYS; + /* GPIOD_ are directly managed by driver in set_dir_flags*/ + if (ops->set_dir_flags) { + ret = ops->set_dir_flags(dev, desc->offset, flags); + } else { + if (flags & GPIOD_IS_OUT) { + ret = ops->direction_output(dev, desc->offset, + GPIOD_FLAGS_OUTPUT(flags)); + } else if (flags & GPIOD_IS_IN) { + ret = ops->direction_input(dev, desc->offset); + } + } + + return ret; } -int dm_gpio_set_open_drain(struct gpio_desc *desc, int value) +int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags) { - struct dm_gpio_ops *ops = gpio_get_ops(desc->dev); int ret; - ret = check_reserved(desc, "set_open_drain"); + ret = check_reserved(desc, "set_dir_flags"); if (ret) return ret; - if (ops->set_open_drain) - ret = ops->set_open_drain(desc->dev, desc->offset, value); - else - return 0; /* feature not supported -> ignore setting */ + /* combine the requested flags (for IN/OUT) and the descriptor flags */ + flags |= desc->flags; + ret = _dm_gpio_set_dir_flags(desc, flags); + + /* update the descriptor flags */ + if (ret) + desc->flags = flags; return ret; } -int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags) +int dm_gpio_set_dir(struct gpio_desc *desc) { - struct udevice *dev = desc->dev; - struct dm_gpio_ops *ops = gpio_get_ops(dev); int ret; ret = check_reserved(desc, "set_dir"); if (ret) return ret; - if (flags & GPIOD_IS_OUT) { - int value = flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0; + return _dm_gpio_set_dir_flags(desc, desc->flags); +} - if (flags & GPIOD_ACTIVE_LOW) - value = !value; - ret = ops->direction_output(dev, desc->offset, value); - } else if (flags & GPIOD_IS_IN) { - ret = ops->direction_input(dev, desc->offset); - } +int dm_gpio_get_dir_flags(struct gpio_desc *desc, ulong *flags) +{ + struct udevice *dev = desc->dev; + int ret, value; + struct dm_gpio_ops *ops = gpio_get_ops(dev); + ulong dir_flags; + + ret = check_reserved(desc, "get_dir_flags"); if (ret) return ret; - /* - * Update desc->flags here, so that GPIO_ACTIVE_LOW is honoured in - * futures - */ - desc->flags = flags; - return 0; -} + /* GPIOD_ are directly provided by driver except GPIOD_ACTIVE_LOW */ + if (ops->get_dir_flags) { + ret = ops->get_dir_flags(dev, desc->offset, &dir_flags); + if (ret) + return ret; -int dm_gpio_set_dir(struct gpio_desc *desc) -{ - return dm_gpio_set_dir_flags(desc, desc->flags); + /* GPIOD_ACTIVE_LOW is saved in desc->flags */ + value = dir_flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0; + if (desc->flags & GPIOD_ACTIVE_LOW) + value = !value; + dir_flags &= ~(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE); + dir_flags |= (desc->flags & GPIOD_ACTIVE_LOW); + if (value) + dir_flags |= GPIOD_IS_OUT_ACTIVE; + } else { + dir_flags = desc->flags; + /* only GPIOD_IS_OUT_ACTIVE is provided by uclass */ + dir_flags &= ~GPIOD_IS_OUT_ACTIVE; + if ((desc->flags & GPIOD_IS_OUT) && _gpio_get_value(desc)) + dir_flags |= GPIOD_IS_OUT_ACTIVE; + } + *flags = dir_flags; + + return 0; } /** @@ -804,9 +900,7 @@ static int gpio_request_tail(int ret, const char *nodename, struct gpio_desc *desc, int flags, bool add_index, struct udevice *gpio_dev) { - desc->dev = gpio_dev; - desc->offset = 0; - desc->flags = 0; + gpio_desc_init(desc, gpio_dev, 0); if (ret) goto err; @@ -830,7 +924,7 @@ static int gpio_request_tail(int ret, const char *nodename, debug("%s: dm_gpio_requestf failed\n", __func__); goto err; } - ret = dm_gpio_set_dir_flags(desc, flags | desc->flags); + ret = dm_gpio_set_dir_flags(desc, flags); if (ret) { debug("%s: dm_gpio_set_dir failed\n", __func__); goto err; @@ -1053,14 +1147,14 @@ static int gpio_post_bind(struct udevice *dev) ops->get_value += gd->reloc_off; if (ops->set_value) ops->set_value += gd->reloc_off; - if (ops->get_open_drain) - ops->get_open_drain += gd->reloc_off; - if (ops->set_open_drain) - ops->set_open_drain += gd->reloc_off; if (ops->get_function) ops->get_function += gd->reloc_off; if (ops->xlate) ops->xlate += gd->reloc_off; + if (ops->set_dir_flags) + ops->set_dir_flags += gd->reloc_off; + if (ops->get_dir_flags) + ops->get_dir_flags += gd->reloc_off; reloc_done++; } diff --git a/drivers/gpio/mpc8xxx_gpio.c b/drivers/gpio/mpc8xxx_gpio.c index 4b385b8b39..1dfd22522c 100644 --- a/drivers/gpio/mpc8xxx_gpio.c +++ b/drivers/gpio/mpc8xxx_gpio.c @@ -133,26 +133,6 @@ static int mpc8xxx_gpio_get_value(struct udevice *dev, uint gpio) return !!mpc8xxx_gpio_get_val(data->base, gpio_mask(gpio)); } -static int mpc8xxx_gpio_get_open_drain(struct udevice *dev, uint gpio) -{ - struct mpc8xxx_gpio_data *data = dev_get_priv(dev); - - return !!mpc8xxx_gpio_open_drain_val(data->base, gpio_mask(gpio)); -} - -static int mpc8xxx_gpio_set_open_drain(struct udevice *dev, uint gpio, - int value) -{ - struct mpc8xxx_gpio_data *data = dev_get_priv(dev); - - if (value) - mpc8xxx_gpio_open_drain_on(data->base, gpio_mask(gpio)); - else - mpc8xxx_gpio_open_drain_off(data->base, gpio_mask(gpio)); - - return 0; -} - static int mpc8xxx_gpio_get_function(struct udevice *dev, uint gpio) { struct mpc8xxx_gpio_data *data = dev_get_priv(dev); @@ -229,8 +209,6 @@ static const struct dm_gpio_ops gpio_mpc8xxx_ops = { .direction_output = mpc8xxx_gpio_direction_output, .get_value = mpc8xxx_gpio_get_value, .set_value = mpc8xxx_gpio_set_value, - .get_open_drain = mpc8xxx_gpio_get_open_drain, - .set_open_drain = mpc8xxx_gpio_set_open_drain, .get_function = mpc8xxx_gpio_get_function, }; diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c index 2ef5c67ad5..9549c74c2b 100644 --- a/drivers/gpio/sandbox.c +++ b/drivers/gpio/sandbox.c @@ -8,43 +8,44 @@ #include <fdtdec.h> #include <malloc.h> #include <asm/gpio.h> +#include <dm/device_compat.h> +#include <dm/lists.h> #include <dm/of.h> +#include <dm/pinctrl.h> #include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/gpio/sandbox-gpio.h> -/* Flags for each GPIO */ -#define GPIOF_OUTPUT (1 << 0) /* Currently set as an output */ -#define GPIOF_HIGH (1 << 1) /* Currently set high */ -#define GPIOF_ODR (1 << 2) /* Currently set to open drain mode */ struct gpio_state { const char *label; /* label given by requester */ - u8 flags; /* flags (GPIOF_...) */ + ulong dir_flags; /* dir_flags (GPIOD_...) */ }; -/* Access routines for GPIO state */ -static u8 *get_gpio_flags(struct udevice *dev, unsigned offset) +/* Access routines for GPIO dir flags */ +static ulong *get_gpio_dir_flags(struct udevice *dev, unsigned int offset) { struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); struct gpio_state *state = dev_get_priv(dev); if (offset >= uc_priv->gpio_count) { - static u8 invalid_flags; + static ulong invalid_dir_flags; printf("sandbox_gpio: error: invalid gpio %u\n", offset); - return &invalid_flags; + return &invalid_dir_flags; } - return &state[offset].flags; + return &state[offset].dir_flags; + } -static int get_gpio_flag(struct udevice *dev, unsigned offset, int flag) +static int get_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag) { - return (*get_gpio_flags(dev, offset) & flag) != 0; + return (*get_gpio_dir_flags(dev, offset) & flag) != 0; } -static int set_gpio_flag(struct udevice *dev, unsigned offset, int flag, +static int set_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag, int value) { - u8 *gpio = get_gpio_flags(dev, offset); + ulong *gpio = get_gpio_dir_flags(dev, offset); if (value) *gpio |= flag; @@ -60,34 +61,40 @@ static int set_gpio_flag(struct udevice *dev, unsigned offset, int flag, int sandbox_gpio_get_value(struct udevice *dev, unsigned offset) { - if (get_gpio_flag(dev, offset, GPIOF_OUTPUT)) + if (get_gpio_flag(dev, offset, GPIOD_IS_OUT)) debug("sandbox_gpio: get_value on output gpio %u\n", offset); - return get_gpio_flag(dev, offset, GPIOF_HIGH); + return get_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE); } int sandbox_gpio_set_value(struct udevice *dev, unsigned offset, int value) { - return set_gpio_flag(dev, offset, GPIOF_HIGH, value); + return set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE, value); } -int sandbox_gpio_get_open_drain(struct udevice *dev, unsigned offset) +int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset) { - return get_gpio_flag(dev, offset, GPIOF_ODR); + return get_gpio_flag(dev, offset, GPIOD_IS_OUT); } -int sandbox_gpio_set_open_drain(struct udevice *dev, unsigned offset, int value) +int sandbox_gpio_set_direction(struct udevice *dev, unsigned offset, int output) { - return set_gpio_flag(dev, offset, GPIOF_ODR, value); + set_gpio_flag(dev, offset, GPIOD_IS_OUT, output); + set_gpio_flag(dev, offset, GPIOD_IS_IN, !(output)); + + return 0; } -int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset) +ulong sandbox_gpio_get_dir_flags(struct udevice *dev, unsigned int offset) { - return get_gpio_flag(dev, offset, GPIOF_OUTPUT); + return *get_gpio_dir_flags(dev, offset); } -int sandbox_gpio_set_direction(struct udevice *dev, unsigned offset, int output) +int sandbox_gpio_set_dir_flags(struct udevice *dev, unsigned int offset, + ulong flags) { - return set_gpio_flag(dev, offset, GPIOF_OUTPUT, output); + *get_gpio_dir_flags(dev, offset) = flags; + + return 0; } /* @@ -134,33 +141,14 @@ static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value) return sandbox_gpio_set_value(dev, offset, value); } -/* read GPIO ODR value of port 'offset' */ -static int sb_gpio_get_open_drain(struct udevice *dev, unsigned offset) -{ - debug("%s: offset:%u\n", __func__, offset); - - return sandbox_gpio_get_open_drain(dev, offset); -} - -/* write GPIO ODR value to port 'offset' */ -static int sb_gpio_set_open_drain(struct udevice *dev, unsigned offset, int value) -{ - debug("%s: offset:%u, value = %d\n", __func__, offset, value); - - if (!sandbox_gpio_get_direction(dev, offset)) { - printf("sandbox_gpio: error: set_open_drain on input gpio %u\n", - offset); - return -1; - } - - return sandbox_gpio_set_open_drain(dev, offset, value); -} - static int sb_gpio_get_function(struct udevice *dev, unsigned offset) { - if (get_gpio_flag(dev, offset, GPIOF_OUTPUT)) + if (get_gpio_flag(dev, offset, GPIOD_IS_OUT)) return GPIOF_OUTPUT; - return GPIOF_INPUT; + if (get_gpio_flag(dev, offset, GPIOD_IS_IN)) + return GPIOF_INPUT; + + return GPIOF_INPUT; /*GPIO is not configurated */ } static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, @@ -169,27 +157,54 @@ static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, desc->offset = args->args[0]; if (args->args_count < 2) return 0; - if (args->args[1] & GPIO_ACTIVE_LOW) - desc->flags |= GPIOD_ACTIVE_LOW; - if (args->args[1] & 2) + /* treat generic binding with gpio uclass */ + gpio_xlate_offs_flags(dev, desc, args); + + /* sandbox test specific, not defined in gpio.h */ + if (args->args[1] & GPIO_IN) desc->flags |= GPIOD_IS_IN; - if (args->args[1] & 4) + + if (args->args[1] & GPIO_OUT) desc->flags |= GPIOD_IS_OUT; - if (args->args[1] & 8) + + if (args->args[1] & GPIO_OUT_ACTIVE) desc->flags |= GPIOD_IS_OUT_ACTIVE; return 0; } +static int sb_gpio_set_dir_flags(struct udevice *dev, unsigned int offset, + ulong flags) +{ + ulong *dir_flags; + + debug("%s: offset:%u, dir_flags = %lx\n", __func__, offset, flags); + + dir_flags = get_gpio_dir_flags(dev, offset); + + *dir_flags = flags; + + return 0; +} + +static int sb_gpio_get_dir_flags(struct udevice *dev, unsigned int offset, + ulong *flags) +{ + debug("%s: offset:%u\n", __func__, offset); + *flags = *get_gpio_dir_flags(dev, offset); + + return 0; +} + static const struct dm_gpio_ops gpio_sandbox_ops = { .direction_input = sb_gpio_direction_input, .direction_output = sb_gpio_direction_output, .get_value = sb_gpio_get_value, .set_value = sb_gpio_set_value, - .get_open_drain = sb_gpio_get_open_drain, - .set_open_drain = sb_gpio_set_open_drain, .get_function = sb_gpio_get_function, .xlate = sb_gpio_xlate, + .set_dir_flags = sb_gpio_set_dir_flags, + .get_dir_flags = sb_gpio_get_dir_flags, }; static int sandbox_gpio_ofdata_to_platdata(struct udevice *dev) @@ -237,3 +252,198 @@ U_BOOT_DRIVER(gpio_sandbox) = { .remove = gpio_sandbox_remove, .ops = &gpio_sandbox_ops, }; + +/* pincontrol: used only to check GPIO pin configuration (pinmux command) */ + +struct sb_pinctrl_priv { + int pinctrl_ngpios; + struct list_head gpio_dev; +}; + +struct sb_gpio_bank { + struct udevice *gpio_dev; + struct list_head list; +}; + +static int sb_populate_gpio_dev_list(struct udevice *dev) +{ + struct sb_pinctrl_priv *priv = dev_get_priv(dev); + struct udevice *gpio_dev; + struct udevice *child; + struct sb_gpio_bank *gpio_bank; + int ret; + + /* + * parse pin-controller sub-nodes (ie gpio bank nodes) and fill + * a list with all gpio device reference which belongs to the + * current pin-controller. This list is used to find pin_name and + * pin muxing + */ + list_for_each_entry(child, &dev->child_head, sibling_node) { + ret = uclass_get_device_by_name(UCLASS_GPIO, child->name, + &gpio_dev); + if (ret < 0) + continue; + + gpio_bank = malloc(sizeof(*gpio_bank)); + if (!gpio_bank) { + dev_err(dev, "Not enough memory\n"); + return -ENOMEM; + } + + gpio_bank->gpio_dev = gpio_dev; + list_add_tail(&gpio_bank->list, &priv->gpio_dev); + } + + return 0; +} + +static int sb_pinctrl_get_pins_count(struct udevice *dev) +{ + struct sb_pinctrl_priv *priv = dev_get_priv(dev); + struct gpio_dev_priv *uc_priv; + struct sb_gpio_bank *gpio_bank; + + /* + * if get_pins_count has already been executed once on this + * pin-controller, no need to run it again + */ + if (priv->pinctrl_ngpios) + return priv->pinctrl_ngpios; + + if (list_empty(&priv->gpio_dev)) + sb_populate_gpio_dev_list(dev); + /* + * walk through all banks to retrieve the pin-controller + * pins number + */ + list_for_each_entry(gpio_bank, &priv->gpio_dev, list) { + uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev); + + priv->pinctrl_ngpios += uc_priv->gpio_count; + } + + return priv->pinctrl_ngpios; +} + +static struct udevice *sb_pinctrl_get_gpio_dev(struct udevice *dev, + unsigned int selector, + unsigned int *idx) +{ + struct sb_pinctrl_priv *priv = dev_get_priv(dev); + struct sb_gpio_bank *gpio_bank; + struct gpio_dev_priv *uc_priv; + int pin_count = 0; + + if (list_empty(&priv->gpio_dev)) + sb_populate_gpio_dev_list(dev); + + /* look up for the bank which owns the requested pin */ + list_for_each_entry(gpio_bank, &priv->gpio_dev, list) { + uc_priv = dev_get_uclass_priv(gpio_bank->gpio_dev); + + if (selector < (pin_count + uc_priv->gpio_count)) { + /* + * we found the bank, convert pin selector to + * gpio bank index + */ + *idx = selector - pin_count; + + return gpio_bank->gpio_dev; + } + pin_count += uc_priv->gpio_count; + } + + return NULL; +} + +static const char *sb_pinctrl_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + struct gpio_dev_priv *uc_priv; + struct udevice *gpio_dev; + unsigned int gpio_idx; + static char pin_name[PINNAME_SIZE]; + + /* look up for the bank which owns the requested pin */ + gpio_dev = sb_pinctrl_get_gpio_dev(dev, selector, &gpio_idx); + if (!gpio_dev) { + snprintf(pin_name, PINNAME_SIZE, "Error"); + } else { + uc_priv = dev_get_uclass_priv(gpio_dev); + + snprintf(pin_name, PINNAME_SIZE, "%s%d", + uc_priv->bank_name, + gpio_idx); + } + + return pin_name; +} + +static char *get_dir_flags_string(ulong flags) +{ + if (flags & GPIOD_OPEN_DRAIN) + return "drive-open-drain"; + if (flags & GPIOD_OPEN_SOURCE) + return "drive-open-source"; + if (flags & GPIOD_PULL_UP) + return "bias-pull-up"; + if (flags & GPIOD_PULL_DOWN) + return "bias-pull-down"; + return "."; +} + +static int sb_pinctrl_get_pin_muxing(struct udevice *dev, + unsigned int selector, + char *buf, int size) +{ + struct udevice *gpio_dev; + unsigned int gpio_idx; + ulong dir_flags; + int function; + + /* look up for the bank which owns the requested pin */ + gpio_dev = sb_pinctrl_get_gpio_dev(dev, selector, &gpio_idx); + if (!gpio_dev) { + snprintf(buf, size, "Error"); + } else { + function = sb_gpio_get_function(gpio_dev, gpio_idx); + dir_flags = *get_gpio_dir_flags(gpio_dev, gpio_idx); + + snprintf(buf, size, "gpio %s %s", + function == GPIOF_OUTPUT ? "output" : "input", + get_dir_flags_string(dir_flags)); + } + + return 0; +} + +static int sandbox_pinctrl_probe(struct udevice *dev) +{ + struct sb_pinctrl_priv *priv = dev_get_priv(dev); + + INIT_LIST_HEAD(&priv->gpio_dev); + + return 0; +} + +static struct pinctrl_ops sandbox_pinctrl_gpio_ops = { + .get_pin_name = sb_pinctrl_get_pin_name, + .get_pins_count = sb_pinctrl_get_pins_count, + .get_pin_muxing = sb_pinctrl_get_pin_muxing, +}; + +static const struct udevice_id sandbox_pinctrl_gpio_match[] = { + { .compatible = "sandbox,pinctrl-gpio" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(sandbox_pinctrl_gpio) = { + .name = "sandbox_pinctrl_gpio", + .id = UCLASS_PINCTRL, + .of_match = sandbox_pinctrl_gpio_match, + .ops = &sandbox_pinctrl_gpio_ops, + .bind = dm_scan_fdt_dev, + .probe = sandbox_pinctrl_probe, + .priv_auto_alloc_size = sizeof(struct sb_pinctrl_priv), +}; diff --git a/drivers/pinctrl/pinctrl-generic.c b/drivers/pinctrl/pinctrl-generic.c index 1098366b5f..313aeccb1e 100644 --- a/drivers/pinctrl/pinctrl-generic.c +++ b/drivers/pinctrl/pinctrl-generic.c @@ -9,8 +9,6 @@ #include <linux/compat.h> #include <dm/pinctrl.h> -DECLARE_GLOBAL_DATA_PTR; - /** * pinctrl_pin_name_to_selector() - return the pin selector for a pin * @@ -244,18 +242,14 @@ static int pinctrl_generic_set_state_one(struct udevice *dev, struct udevice *config, bool is_group, unsigned selector) { - const void *fdt = gd->fdt_blob; - int node_offset = dev_of_offset(config); const char *propname; const void *value; - int prop_offset, len, func_selector, param, ret; + struct ofprop property; + int len, func_selector, param, ret; u32 arg, default_val; - for (prop_offset = fdt_first_property_offset(fdt, node_offset); - prop_offset > 0; - prop_offset = fdt_next_property_offset(fdt, prop_offset)) { - value = fdt_getprop_by_offset(fdt, prop_offset, - &propname, &len); + dev_for_each_property(property, config) { + value = dev_read_prop_by_prop(&property, &propname, &len); if (!value) return -EINVAL; @@ -299,19 +293,17 @@ static int pinctrl_generic_set_state_one(struct udevice *dev, static int pinctrl_generic_set_state_subnode(struct udevice *dev, struct udevice *config) { - const void *fdt = gd->fdt_blob; - int node = dev_of_offset(config); const char *subnode_target_type = "pins"; bool is_group = false; const char *name; int strings_count, selector, i, ret; - strings_count = fdt_stringlist_count(fdt, node, subnode_target_type); + strings_count = dev_read_string_count(config, subnode_target_type); if (strings_count < 0) { subnode_target_type = "groups"; is_group = true; - strings_count = fdt_stringlist_count(fdt, node, - subnode_target_type); + strings_count = dev_read_string_count(config, + subnode_target_type); if (strings_count < 0) { /* skip this node; may contain config child nodes */ return 0; @@ -319,10 +311,10 @@ static int pinctrl_generic_set_state_subnode(struct udevice *dev, } for (i = 0; i < strings_count; i++) { - name = fdt_stringlist_get(fdt, node, subnode_target_type, i, - NULL); - if (!name) - return -EINVAL; + ret = dev_read_string_index(config, subnode_target_type, i, + &name); + if (ret) + return ret; if (is_group) selector = pinctrl_group_name_to_selector(dev, name); diff --git a/drivers/pinctrl/pinctrl-sandbox.c b/drivers/pinctrl/pinctrl-sandbox.c index 0786afe747..3ee75fbbee 100644 --- a/drivers/pinctrl/pinctrl-sandbox.c +++ b/drivers/pinctrl/pinctrl-sandbox.c @@ -14,7 +14,11 @@ static const char * const sandbox_pins[] = { "SDA", "TX", "RX", - "W1" + "W1", + "GPIO0", + "GPIO1", + "GPIO2", + "GPIO3", }; static const char * const sandbox_pins_muxing[] = { @@ -23,6 +27,10 @@ static const char * const sandbox_pins_muxing[] = { "Uart TX", "Uart RX", "1-wire gpio", + "gpio", + "gpio", + "gpio", + "gpio", }; static const char * const sandbox_groups[] = { @@ -38,6 +46,10 @@ static const char * const sandbox_functions[] = { "serial", "spi", "w1", + "gpio", + "gpio", + "gpio", + "gpio", }; static const struct pinconf_param sandbox_conf_params[] = { @@ -54,6 +66,10 @@ static const struct pinconf_param sandbox_conf_params[] = { { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 }, }; +/* bitfield used to save param and value of each pin/selector */ +static unsigned int sandbox_pins_param[ARRAY_SIZE(sandbox_pins)]; +static unsigned int sandbox_pins_value[ARRAY_SIZE(sandbox_pins)]; + static int sandbox_get_pins_count(struct udevice *dev) { return ARRAY_SIZE(sandbox_pins); @@ -68,8 +84,25 @@ static int sandbox_get_pin_muxing(struct udevice *dev, unsigned int selector, char *buf, int size) { + const struct pinconf_param *p; + int i; + snprintf(buf, size, "%s", sandbox_pins_muxing[selector]); + if (sandbox_pins_param[selector]) { + for (i = 0, p = sandbox_conf_params; + i < ARRAY_SIZE(sandbox_conf_params); + i++, p++) { + if ((sandbox_pins_param[selector] & BIT(p->param)) && + (!!(sandbox_pins_value[selector] & BIT(p->param)) == + p->default_value)) { + strncat(buf, " ", size); + strncat(buf, p->property, size); + } + } + } + strncat(buf, ".", size); + return 0; } @@ -102,6 +135,9 @@ static int sandbox_pinmux_set(struct udevice *dev, unsigned pin_selector, pin_selector, sandbox_get_pin_name(dev, pin_selector), func_selector, sandbox_get_function_name(dev, func_selector)); + sandbox_pins_param[pin_selector] = 0; + sandbox_pins_value[pin_selector] = 0; + return 0; } @@ -123,6 +159,12 @@ static int sandbox_pinconf_set(struct udevice *dev, unsigned pin_selector, pin_selector, sandbox_get_pin_name(dev, pin_selector), param, argument); + sandbox_pins_param[pin_selector] |= BIT(param); + if (argument) + sandbox_pins_value[pin_selector] |= BIT(param); + else + sandbox_pins_value[pin_selector] &= ~BIT(param); + return 0; } diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 380b0da271..a5d1ff0e97 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -10,8 +10,6 @@ #include <linux/libfdt.h> #include <asm/io.h> -DECLARE_GLOBAL_DATA_PTR; - struct single_pdata { fdt_addr_t base; /* first configuration register */ int offset; /* index of last configuration register */ @@ -118,13 +116,11 @@ static int single_configure_bits(struct udevice *dev, static int single_set_state(struct udevice *dev, struct udevice *config) { - const void *fdt = gd->fdt_blob; const struct single_fdt_pin_cfg *prop; const struct single_fdt_bits_cfg *prop_bits; int len; - prop = fdt_getprop(fdt, dev_of_offset(config), "pinctrl-single,pins", - &len); + prop = dev_read_prop(dev, "pinctrl-single,pins", &len); if (prop) { dev_dbg(dev, "configuring pins for %s\n", config->name); @@ -137,9 +133,7 @@ static int single_set_state(struct udevice *dev, } /* pinctrl-single,pins not found so check for pinctrl-single,bits */ - prop_bits = fdt_getprop(fdt, dev_of_offset(config), - "pinctrl-single,bits", - &len); + prop_bits = dev_read_prop(dev, "pinctrl-single,bits", &len); if (prop_bits) { dev_dbg(dev, "configuring pins for %s\n", config->name); if (len % sizeof(struct single_fdt_bits_cfg)) { @@ -161,27 +155,24 @@ static int single_ofdata_to_platdata(struct udevice *dev) int res; struct single_pdata *pdata = dev->platdata; - pdata->width = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "pinctrl-single,register-width", 0); + pdata->width = + dev_read_u32_default(dev, "pinctrl-single,register-width", 0); - res = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev), - "reg", of_reg, 2); + res = dev_read_u32_array(dev, "reg", of_reg, 2); if (res) return res; pdata->offset = of_reg[1] - pdata->width / 8; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) { dev_dbg(dev, "no valid base register address\n"); return -EINVAL; } pdata->base = addr; - pdata->mask = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "pinctrl-single,function-mask", - 0xffffffff); - pdata->bits_per_mux = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev), - "pinctrl-single,bit-per-mux"); + pdata->mask = dev_read_u32_default(dev, "pinctrl-single,function-mask", + 0xffffffff); + pdata->bits_per_mux = dev_read_bool(dev, "pinctrl-single,bit-per-mux"); return 0; } |