1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (c), Vaisala Oyj 4 */ 5 6#include <asm/gpio.h> 7#include <dm.h> 8#include <dm/devres.h> 9#include <errno.h> 10#include <reboot-mode/reboot-mode-gpio.h> 11#include <reboot-mode/reboot-mode.h> 12 13DECLARE_GLOBAL_DATA_PTR; 14 15static int reboot_mode_get(struct udevice *dev, u32 *buf) 16{ 17 int ret; 18 struct reboot_mode_gpio_platdata *plat_data; 19 20 if (!buf) 21 return -EINVAL; 22 23 plat_data = dev_get_plat(dev); 24 if (!plat_data) 25 return -EINVAL; 26 27 ret = dm_gpio_get_values_as_int(plat_data->gpio_desc, 28 plat_data->gpio_count); 29 if (ret < 0) 30 return ret; 31 32 *buf = ret; 33 34 return 0; 35} 36 37static int reboot_mode_probe(struct udevice *dev) 38{ 39 struct reboot_mode_gpio_platdata *plat_data; 40 41 plat_data = dev_get_plat(dev); 42 if (!plat_data) 43 return -EINVAL; 44 45 int ret; 46 47#if CONFIG_IS_ENABLED(OF_CONTROL) 48 ret = gpio_get_list_count(dev, "gpios"); 49 if (ret < 0) 50 return ret; 51 52 plat_data->gpio_count = ret; 53#endif 54 55 if (plat_data->gpio_count <= 0) 56 return -EINVAL; 57 58 plat_data->gpio_desc = devm_kcalloc(dev, plat_data->gpio_count, 59 sizeof(struct gpio_desc), 0); 60 if (!plat_data->gpio_desc) 61 return -ENOMEM; 62 63#if CONFIG_IS_ENABLED(OF_CONTROL) 64 ret = gpio_request_list_by_name(dev, "gpios", plat_data->gpio_desc, 65 plat_data->gpio_count, GPIOD_IS_IN); 66 if (ret < 0) 67 return ret; 68#else 69 for (int i = 0; i < plat_data->gpio_count; i++) { 70 struct reboot_mode_gpio_config *gpio = 71 plat_data->gpios_config + i; 72 struct gpio_desc *desc = plat_data->gpio_desc + i; 73 74 ret = uclass_get_device_by_seq(UCLASS_GPIO, 75 gpio->gpio_dev_offset, 76 &desc->dev); 77 if (ret < 0) 78 return ret; 79 80 desc->flags = gpio->flags; 81 desc->offset = gpio->gpio_offset; 82 83 ret = dm_gpio_request(desc, ""); 84 if (ret < 0) 85 return ret; 86 87 ret = dm_gpio_set_dir(desc); 88 if (ret < 0) 89 return ret; 90 } 91#endif 92 return 0; 93} 94 95static int reboot_mode_remove(struct udevice *dev) 96{ 97 struct reboot_mode_gpio_platdata *plat_data; 98 99 plat_data = dev_get_plat(dev); 100 if (!plat_data) 101 return -EINVAL; 102 103 return gpio_free_list(dev, plat_data->gpio_desc, plat_data->gpio_count); 104} 105 106#if CONFIG_IS_ENABLED(OF_CONTROL) 107static const struct udevice_id reboot_mode_ids[] = { 108 { .compatible = "reboot-mode-gpio", 0 }, 109 { } 110}; 111#endif 112 113static const struct reboot_mode_ops reboot_mode_gpio_ops = { 114 .get = reboot_mode_get, 115}; 116 117U_BOOT_DRIVER(reboot_mode_gpio) = { 118 .name = "reboot-mode-gpio", 119 .id = UCLASS_REBOOT_MODE, 120 .probe = reboot_mode_probe, 121 .remove = reboot_mode_remove, 122#if CONFIG_IS_ENABLED(OF_CONTROL) 123 .of_match = reboot_mode_ids, 124#endif 125 .plat_auto = sizeof(struct reboot_mode_gpio_platdata), 126 .ops = &reboot_mode_gpio_ops, 127}; 128