mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-10-26 17:48:26 +00:00 
			
		
		
		
	This uses the newly-added dm_gpio_get_values_as_int_base3 function to implement a sysinfo device. The revision map is stored in the device tree. Signed-off-by: Sean Anderson <sean.anderson@seco.com> Reviewed-by: Simon Glass <sjg@chromium.org>
		
			
				
	
	
		
			142 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			142 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0+
 | |
| /*
 | |
|  * Copyright (C) 2021 Sean Anderson <sean.anderson@seco.com>
 | |
|  */
 | |
| 
 | |
| #include <common.h>
 | |
| #include <dm.h>
 | |
| #include <log.h>
 | |
| #include <sysinfo.h>
 | |
| #include <asm/gpio.h>
 | |
| #include <dm/device_compat.h>
 | |
| 
 | |
| /**
 | |
|  * struct sysinfo_gpio_priv - GPIO sysinfo private data
 | |
|  * @gpios: List of GPIOs used to detect the revision
 | |
|  * @gpio_num: The number of GPIOs in @gpios
 | |
|  * @revision: The revision as detected from the GPIOs.
 | |
|  */
 | |
| struct sysinfo_gpio_priv {
 | |
| 	struct gpio_desc *gpios;
 | |
| 	int gpio_num, revision;
 | |
| };
 | |
| 
 | |
| static int sysinfo_gpio_detect(struct udevice *dev)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct sysinfo_gpio_priv *priv = dev_get_priv(dev);
 | |
| 
 | |
| 	ret = dm_gpio_get_values_as_int_base3(priv->gpios, priv->gpio_num);
 | |
| 	if (ret < 0)
 | |
| 		return ret;
 | |
| 
 | |
| 	priv->revision = ret;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int sysinfo_gpio_get_int(struct udevice *dev, int id, int *val)
 | |
| {
 | |
| 	struct sysinfo_gpio_priv *priv = dev_get_priv(dev);
 | |
| 
 | |
| 	switch (id) {
 | |
| 	case SYSINFO_ID_BOARD_MODEL:
 | |
| 		*val = priv->revision;
 | |
| 		return 0;
 | |
| 	default:
 | |
| 		return -EINVAL;
 | |
| 	};
 | |
| }
 | |
| 
 | |
| static int sysinfo_gpio_get_str(struct udevice *dev, int id, size_t size, char *val)
 | |
| {
 | |
| 	struct sysinfo_gpio_priv *priv = dev_get_priv(dev);
 | |
| 
 | |
| 	switch (id) {
 | |
| 	case SYSINFO_ID_BOARD_MODEL: {
 | |
| 		const char *name = NULL;
 | |
| 		int i, ret;
 | |
| 		u32 revision;
 | |
| 
 | |
| 		for (i = 0; i < priv->gpio_num; i++) {
 | |
| 			ret = dev_read_u32_index(dev, "revisions", i,
 | |
| 						 &revision);
 | |
| 			if (ret) {
 | |
| 				if (ret != -EOVERFLOW)
 | |
| 					return ret;
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			if (revision == priv->revision) {
 | |
| 				ret = dev_read_string_index(dev, "names", i,
 | |
| 							    &name);
 | |
| 				if (ret < 0)
 | |
| 					return ret;
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 		if (!name)
 | |
| 			name = "unknown";
 | |
| 
 | |
| 		strncpy(val, name, size);
 | |
| 		val[size - 1] = '\0';
 | |
| 		return 0;
 | |
| 	} default:
 | |
| 		return -EINVAL;
 | |
| 	};
 | |
| }
 | |
| 
 | |
| static const struct sysinfo_ops sysinfo_gpio_ops = {
 | |
| 	.detect = sysinfo_gpio_detect,
 | |
| 	.get_int = sysinfo_gpio_get_int,
 | |
| 	.get_str = sysinfo_gpio_get_str,
 | |
| };
 | |
| 
 | |
| static int sysinfo_gpio_probe(struct udevice *dev)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct sysinfo_gpio_priv *priv = dev_get_priv(dev);
 | |
| 
 | |
| 	priv->gpio_num = gpio_get_list_count(dev, "gpios");
 | |
| 	if (priv->gpio_num < 0) {
 | |
| 		dev_err(dev, "could not get gpios length (err = %d)\n",
 | |
| 			priv->gpio_num);
 | |
| 		return priv->gpio_num;
 | |
| 	}
 | |
| 
 | |
| 	priv->gpios = calloc(priv->gpio_num, sizeof(*priv->gpios));
 | |
| 	if (!priv->gpios) {
 | |
| 		dev_err(dev, "could not allocate memory for %d gpios\n",
 | |
| 			priv->gpio_num);
 | |
| 		return -ENOMEM;
 | |
| 	}
 | |
| 
 | |
| 	ret = gpio_request_list_by_name(dev, "gpios", priv->gpios,
 | |
| 					priv->gpio_num, GPIOD_IS_IN);
 | |
| 	if (ret != priv->gpio_num) {
 | |
| 		dev_err(dev, "could not get gpios (err = %d)\n",
 | |
| 			priv->gpio_num);
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	if (!dev_read_bool(dev, "revisions") || !dev_read_bool(dev, "names")) {
 | |
| 		dev_err(dev, "revisions or names properties missing\n");
 | |
| 		return -ENOENT;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static const struct udevice_id sysinfo_gpio_ids[] = {
 | |
| 	{ .compatible = "gpio-sysinfo" },
 | |
| 	{ /* sentinel */ }
 | |
| };
 | |
| 
 | |
| U_BOOT_DRIVER(sysinfo_gpio) = {
 | |
| 	.name           = "sysinfo_gpio",
 | |
| 	.id             = UCLASS_SYSINFO,
 | |
| 	.of_match       = sysinfo_gpio_ids,
 | |
| 	.ops		= &sysinfo_gpio_ops,
 | |
| 	.priv_auto	= sizeof(struct sysinfo_gpio_priv),
 | |
| 	.probe          = sysinfo_gpio_probe,
 | |
| };
 |