123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Copyright (c) 2011 The Chromium OS Authors.
- */
- #include <common.h>
- #include <dm.h>
- #include <fdtdec.h>
- #include <log.h>
- #include <malloc.h>
- #include <acpi/acpi_device.h>
- #include <asm/gpio.h>
- #include <dm/acpi.h>
- #include <dm/device-internal.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>
- struct gpio_state {
- const char *label; /* label given by requester */
- ulong dir_flags; /* dir_flags (GPIOD_...) */
- };
- /* 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 ulong invalid_dir_flags;
- printf("sandbox_gpio: error: invalid gpio %u\n", offset);
- return &invalid_dir_flags;
- }
- return &state[offset].dir_flags;
- }
- static int get_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag)
- {
- return (*get_gpio_dir_flags(dev, offset) & flag) != 0;
- }
- static int set_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag,
- int value)
- {
- ulong *gpio = get_gpio_dir_flags(dev, offset);
- if (value)
- *gpio |= flag;
- else
- *gpio &= ~flag;
- return 0;
- }
- /*
- * Back-channel sandbox-internal-only access to GPIO state
- */
- int sandbox_gpio_get_value(struct udevice *dev, unsigned offset)
- {
- 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, GPIOD_IS_OUT_ACTIVE);
- }
- int sandbox_gpio_set_value(struct udevice *dev, unsigned offset, int value)
- {
- return set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE, value);
- }
- int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset)
- {
- return get_gpio_flag(dev, offset, GPIOD_IS_OUT);
- }
- int sandbox_gpio_set_direction(struct udevice *dev, unsigned offset, int output)
- {
- set_gpio_flag(dev, offset, GPIOD_IS_OUT, output);
- set_gpio_flag(dev, offset, GPIOD_IS_IN, !(output));
- return 0;
- }
- ulong sandbox_gpio_get_dir_flags(struct udevice *dev, unsigned int offset)
- {
- return *get_gpio_dir_flags(dev, offset);
- }
- int sandbox_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
- ulong flags)
- {
- *get_gpio_dir_flags(dev, offset) = flags;
- return 0;
- }
- /*
- * These functions implement the public interface within U-Boot
- */
- /* set GPIO port 'offset' as an input */
- static int sb_gpio_direction_input(struct udevice *dev, unsigned offset)
- {
- debug("%s: offset:%u\n", __func__, offset);
- return sandbox_gpio_set_direction(dev, offset, 0);
- }
- /* set GPIO port 'offset' as an output, with polarity 'value' */
- static int sb_gpio_direction_output(struct udevice *dev, unsigned offset,
- int value)
- {
- debug("%s: offset:%u, value = %d\n", __func__, offset, value);
- return sandbox_gpio_set_direction(dev, offset, 1) |
- sandbox_gpio_set_value(dev, offset, value);
- }
- /* read GPIO IN value of port 'offset' */
- static int sb_gpio_get_value(struct udevice *dev, unsigned offset)
- {
- debug("%s: offset:%u\n", __func__, offset);
- return sandbox_gpio_get_value(dev, offset);
- }
- /* write GPIO OUT value to port 'offset' */
- static int sb_gpio_set_value(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_value on input gpio %u\n",
- offset);
- return -1;
- }
- return sandbox_gpio_set_value(dev, offset, value);
- }
- static int sb_gpio_get_function(struct udevice *dev, unsigned offset)
- {
- if (get_gpio_flag(dev, offset, GPIOD_IS_OUT))
- return GPIOF_OUTPUT;
- 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,
- struct ofnode_phandle_args *args)
- {
- desc->offset = args->args[0];
- if (args->args_count < 2)
- return 0;
- /* 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] & GPIO_OUT)
- desc->flags |= GPIOD_IS_OUT;
- 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);
- /*
- * For testing purposes keep the output value when switching to input.
- * This allows us to manipulate the input value via the gpio command.
- */
- if (flags & GPIOD_IS_IN)
- *dir_flags = (flags & ~GPIOD_IS_OUT_ACTIVE) |
- (*dir_flags & GPIOD_IS_OUT_ACTIVE);
- else
- *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;
- }
- #if CONFIG_IS_ENABLED(ACPIGEN)
- static int sb_gpio_get_acpi(const struct gpio_desc *desc,
- struct acpi_gpio *gpio)
- {
- int ret;
- /* Note that gpio_get_acpi() zeroes *gpio before calling here */
- gpio->pin_count = 1;
- gpio->pins[0] = desc->offset;
- ret = acpi_device_scope(desc->dev, gpio->resource,
- sizeof(gpio->resource));
- if (ret)
- return log_ret(ret);
- /* All of these values are just used for testing */
- if (desc->flags & GPIOD_ACTIVE_LOW) {
- gpio->pin0_addr = 0x80012 + desc->offset;
- gpio->type = ACPI_GPIO_TYPE_INTERRUPT;
- gpio->pull = ACPI_GPIO_PULL_DOWN;
- gpio->interrupt_debounce_timeout = 4321;
- /* We use the GpioInt part */
- gpio->irq.pin = desc->offset;
- gpio->irq.polarity = ACPI_IRQ_ACTIVE_BOTH;
- gpio->irq.shared = ACPI_IRQ_SHARED;
- gpio->irq.wake = ACPI_IRQ_WAKE;
- /* The GpioIo part is only used for testing */
- gpio->polarity = ACPI_GPIO_ACTIVE_LOW;
- } else {
- gpio->pin0_addr = 0xc00dc + desc->offset;
- gpio->type = ACPI_GPIO_TYPE_IO;
- gpio->pull = ACPI_GPIO_PULL_UP;
- gpio->interrupt_debounce_timeout = 0;
- /* The GpioInt part is not used */
- /* We use the GpioIo part */
- gpio->output_drive_strength = 1234;
- gpio->io_shared = true;
- gpio->io_restrict = ACPI_GPIO_IO_RESTRICT_INPUT;
- gpio->polarity = 0;
- }
- return 0;
- }
- static int sb_gpio_get_name(const struct udevice *dev, char *out_name)
- {
- return acpi_copy_name(out_name, "GPIO");
- }
- struct acpi_ops gpio_sandbox_acpi_ops = {
- .get_name = sb_gpio_get_name,
- };
- #endif /* ACPIGEN */
- 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_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,
- #if CONFIG_IS_ENABLED(ACPIGEN)
- .get_acpi = sb_gpio_get_acpi,
- #endif
- };
- static int sandbox_gpio_of_to_plat(struct udevice *dev)
- {
- struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
- uc_priv->gpio_count = dev_read_u32_default(dev, "sandbox,gpio-count",
- 0);
- uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
- return 0;
- }
- static int gpio_sandbox_probe(struct udevice *dev)
- {
- struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
- if (!dev_has_ofnode(dev))
- /* Tell the uclass how many GPIOs we have */
- uc_priv->gpio_count = CONFIG_SANDBOX_GPIO_COUNT;
- dev_set_priv(dev,
- calloc(sizeof(struct gpio_state), uc_priv->gpio_count));
- return 0;
- }
- static int gpio_sandbox_remove(struct udevice *dev)
- {
- free(dev_get_priv(dev));
- return 0;
- }
- static const struct udevice_id sandbox_gpio_ids[] = {
- { .compatible = "sandbox,gpio" },
- { }
- };
- U_BOOT_DRIVER(sandbox_gpio) = {
- .name = "sandbox_gpio",
- .id = UCLASS_GPIO,
- .of_match = sandbox_gpio_ids,
- .of_to_plat = sandbox_gpio_of_to_plat,
- .probe = gpio_sandbox_probe,
- .remove = gpio_sandbox_remove,
- .ops = &gpio_sandbox_ops,
- ACPI_OPS_PTR(&gpio_sandbox_acpi_ops)
- };
- DM_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias)
- /* 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;
- }
- #if CONFIG_IS_ENABLED(ACPIGEN)
- static int sb_pinctrl_get_name(const struct udevice *dev, char *out_name)
- {
- return acpi_copy_name(out_name, "PINC");
- }
- #endif
- 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,
- };
- #if CONFIG_IS_ENABLED(ACPIGEN)
- struct acpi_ops pinctrl_sandbox_acpi_ops = {
- .get_name = sb_pinctrl_get_name,
- };
- #endif
- 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 = sizeof(struct sb_pinctrl_priv),
- ACPI_OPS_PTR(&pinctrl_sandbox_acpi_ops)
- };
|