diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/reboot-mode/Kconfig | 9 | ||||
-rw-r--r-- | drivers/reboot-mode/Makefile | 1 | ||||
-rw-r--r-- | drivers/reboot-mode/reboot-mode-gpio.c | 128 |
3 files changed, 138 insertions, 0 deletions
diff --git a/drivers/reboot-mode/Kconfig b/drivers/reboot-mode/Kconfig index 0edc3209d7..ff65e2031a 100644 --- a/drivers/reboot-mode/Kconfig +++ b/drivers/reboot-mode/Kconfig @@ -15,4 +15,13 @@ config DM_REBOOT_MODE adjust the boot process based on reboot mode parameter passed to U-Boot. +config DM_REBOOT_MODE_GPIO + bool "Use GPIOs as reboot mode backend" + depends on DM_REBOOT_MODE + default n + help + Use GPIOs to control the reboot mode. This will allow users to boot + a device in a specific mode by using a GPIO that can be controlled + outside U-Boot. + endmenu diff --git a/drivers/reboot-mode/Makefile b/drivers/reboot-mode/Makefile index 2ab0fddac9..04917be4f4 100644 --- a/drivers/reboot-mode/Makefile +++ b/drivers/reboot-mode/Makefile @@ -5,3 +5,4 @@ # obj-$(CONFIG_DM_REBOOT_MODE) += reboot-mode-uclass.o +obj-$(CONFIG_DM_REBOOT_MODE_GPIO) += reboot-mode-gpio.o diff --git a/drivers/reboot-mode/reboot-mode-gpio.c b/drivers/reboot-mode/reboot-mode-gpio.c new file mode 100644 index 0000000000..305174736e --- /dev/null +++ b/drivers/reboot-mode/reboot-mode-gpio.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c), Vaisala Oyj + */ + +#include <common.h> +#include <asm/gpio.h> +#include <dm.h> +#include <dm/devres.h> +#include <errno.h> +#include <reboot-mode/reboot-mode-gpio.h> +#include <reboot-mode/reboot-mode.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int reboot_mode_get(struct udevice *dev, u32 *buf) +{ + int ret; + struct reboot_mode_gpio_platdata *plat_data; + + if (!buf) + return -EINVAL; + + plat_data = dev_get_plat(dev); + if (!plat_data) + return -EINVAL; + + ret = dm_gpio_get_values_as_int(plat_data->gpio_desc, + plat_data->gpio_count); + if (ret < 0) + return ret; + + *buf = ret; + + return 0; +} + +static int reboot_mode_probe(struct udevice *dev) +{ + struct reboot_mode_gpio_platdata *plat_data; + + plat_data = dev_get_plat(dev); + if (!plat_data) + return -EINVAL; + + int ret; + +#if CONFIG_IS_ENABLED(OF_CONTROL) + ret = gpio_get_list_count(dev, "gpios"); + if (ret < 0) + return ret; + + plat_data->gpio_count = ret; +#endif + + if (plat_data->gpio_count <= 0) + return -EINVAL; + + plat_data->gpio_desc = devm_kcalloc(dev, plat_data->gpio_count, + sizeof(struct gpio_desc), 0); + if (!plat_data->gpio_desc) + return -ENOMEM; + +#if CONFIG_IS_ENABLED(OF_CONTROL) + ret = gpio_request_list_by_name(dev, "gpios", plat_data->gpio_desc, + plat_data->gpio_count, GPIOD_IS_IN); + if (ret < 0) + return ret; +#else + for (int i = 0; i < plat_data->gpio_count; i++) { + struct reboot_mode_gpio_config *gpio = + plat_data->gpios_config + i; + struct gpio_desc *desc = plat_data->gpio_desc + i; + + ret = uclass_get_device_by_seq(UCLASS_GPIO, + gpio->gpio_dev_offset, + &desc->dev); + if (ret < 0) + return ret; + + desc->flags = gpio->flags; + desc->offset = gpio->gpio_offset; + + ret = dm_gpio_request(desc, ""); + if (ret < 0) + return ret; + + ret = dm_gpio_set_dir(desc); + if (ret < 0) + return ret; + } +#endif + return 0; +} + +static int reboot_mode_remove(struct udevice *dev) +{ + struct reboot_mode_gpio_platdata *plat_data; + + plat_data = dev_get_plat(dev); + if (!plat_data) + return -EINVAL; + + return gpio_free_list(dev, plat_data->gpio_desc, plat_data->gpio_count); +} + +#if CONFIG_IS_ENABLED(OF_CONTROL) +static const struct udevice_id reboot_mode_ids[] = { + { .compatible = "reboot-mode-gpio", 0 }, + { } +}; +#endif + +static const struct reboot_mode_ops reboot_mode_gpio_ops = { + .get = reboot_mode_get, +}; + +U_BOOT_DRIVER(reboot_mode_gpio) = { + .name = "reboot-mode-gpio", + .id = UCLASS_REBOOT_MODE, + .probe = reboot_mode_probe, + .remove = reboot_mode_remove, +#if CONFIG_IS_ENABLED(OF_CONTROL) + .of_match = reboot_mode_ids, +#endif + .plat_auto = sizeof(struct reboot_mode_gpio_platdata), + .ops = &reboot_mode_gpio_ops, +}; |