xref: /openbmc/u-boot/drivers/gpio/gpio-uclass.c (revision d44f597b12b8f8099c3c52c3eb09540966cafe79)
196495d90SSimon Glass /*
296495d90SSimon Glass  * Copyright (c) 2013 Google, Inc
396495d90SSimon Glass  *
496495d90SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
596495d90SSimon Glass  */
696495d90SSimon Glass 
796495d90SSimon Glass #include <common.h>
896495d90SSimon Glass #include <dm.h>
996495d90SSimon Glass #include <errno.h>
10b892d127SSimon Glass #include <malloc.h>
1196495d90SSimon Glass #include <asm/gpio.h>
12fe1ef503SSimon Glass #include <linux/ctype.h>
1396495d90SSimon Glass 
1496495d90SSimon Glass /**
1596495d90SSimon Glass  * gpio_to_device() - Convert global GPIO number to device, number
1696495d90SSimon Glass  * gpio:	The numeric representation of the GPIO
1796495d90SSimon Glass  *
1896495d90SSimon Glass  * Convert the GPIO number to an entry in the list of GPIOs
1996495d90SSimon Glass  * or GPIO blocks registered with the GPIO controller. Returns
2096495d90SSimon Glass  * entry on success, NULL on error.
2196495d90SSimon Glass  */
2254c5d08aSHeiko Schocher static int gpio_to_device(unsigned int gpio, struct udevice **devp,
2396495d90SSimon Glass 			  unsigned int *offset)
2496495d90SSimon Glass {
2596495d90SSimon Glass 	struct gpio_dev_priv *uc_priv;
2654c5d08aSHeiko Schocher 	struct udevice *dev;
2796495d90SSimon Glass 	int ret;
2896495d90SSimon Glass 
2996495d90SSimon Glass 	for (ret = uclass_first_device(UCLASS_GPIO, &dev);
3096495d90SSimon Glass 	     dev;
3196495d90SSimon Glass 	     ret = uclass_next_device(&dev)) {
3296495d90SSimon Glass 		uc_priv = dev->uclass_priv;
3396495d90SSimon Glass 		if (gpio >= uc_priv->gpio_base &&
3496495d90SSimon Glass 		    gpio < uc_priv->gpio_base + uc_priv->gpio_count) {
3596495d90SSimon Glass 			*devp = dev;
3696495d90SSimon Glass 			*offset = gpio - uc_priv->gpio_base;
3796495d90SSimon Glass 			return 0;
3896495d90SSimon Glass 		}
3996495d90SSimon Glass 	}
4096495d90SSimon Glass 
4196495d90SSimon Glass 	/* No such GPIO */
4296495d90SSimon Glass 	return ret ? ret : -EINVAL;
4396495d90SSimon Glass }
4496495d90SSimon Glass 
4554c5d08aSHeiko Schocher int gpio_lookup_name(const char *name, struct udevice **devp,
4696495d90SSimon Glass 		     unsigned int *offsetp, unsigned int *gpiop)
4796495d90SSimon Glass {
48fe1ef503SSimon Glass 	struct gpio_dev_priv *uc_priv = NULL;
4954c5d08aSHeiko Schocher 	struct udevice *dev;
50fe1ef503SSimon Glass 	ulong offset;
51fe1ef503SSimon Glass 	int numeric;
5296495d90SSimon Glass 	int ret;
5396495d90SSimon Glass 
5496495d90SSimon Glass 	if (devp)
5596495d90SSimon Glass 		*devp = NULL;
56fe1ef503SSimon Glass 	numeric = isdigit(*name) ? simple_strtoul(name, NULL, 10) : -1;
5796495d90SSimon Glass 	for (ret = uclass_first_device(UCLASS_GPIO, &dev);
5896495d90SSimon Glass 	     dev;
5996495d90SSimon Glass 	     ret = uclass_next_device(&dev)) {
6096495d90SSimon Glass 		int len;
6196495d90SSimon Glass 
6296495d90SSimon Glass 		uc_priv = dev->uclass_priv;
63fe1ef503SSimon Glass 		if (numeric != -1) {
64fe1ef503SSimon Glass 			offset = numeric - uc_priv->gpio_base;
65fe1ef503SSimon Glass 			/* Allow GPIOs to be numbered from 0 */
66fe1ef503SSimon Glass 			if (offset >= 0 && offset < uc_priv->gpio_count)
67fe1ef503SSimon Glass 				break;
68fe1ef503SSimon Glass 		}
69fe1ef503SSimon Glass 
7096495d90SSimon Glass 		len = uc_priv->bank_name ? strlen(uc_priv->bank_name) : 0;
7196495d90SSimon Glass 
72939cda5bSSimon Glass 		if (!strncasecmp(name, uc_priv->bank_name, len)) {
73fe1ef503SSimon Glass 			if (!strict_strtoul(name + len, 10, &offset))
74fe1ef503SSimon Glass 				break;
75fe1ef503SSimon Glass 		}
76fe1ef503SSimon Glass 	}
77fe1ef503SSimon Glass 
78fe1ef503SSimon Glass 	if (!dev)
79fe1ef503SSimon Glass 		return ret ? ret : -EINVAL;
80fe1ef503SSimon Glass 
8196495d90SSimon Glass 	if (devp)
8296495d90SSimon Glass 		*devp = dev;
8396495d90SSimon Glass 	if (offsetp)
8496495d90SSimon Glass 		*offsetp = offset;
8596495d90SSimon Glass 	if (gpiop)
8696495d90SSimon Glass 		*gpiop = uc_priv->gpio_base + offset;
8796495d90SSimon Glass 
88fe1ef503SSimon Glass 	return 0;
8996495d90SSimon Glass }
9096495d90SSimon Glass 
9196495d90SSimon Glass /**
9296495d90SSimon Glass  * gpio_request() - [COMPAT] Request GPIO
9396495d90SSimon Glass  * gpio:	GPIO number
9496495d90SSimon Glass  * label:	Name for the requested GPIO
9596495d90SSimon Glass  *
96b892d127SSimon Glass  * The label is copied and allocated so the caller does not need to keep
97b892d127SSimon Glass  * the pointer around.
98b892d127SSimon Glass  *
9996495d90SSimon Glass  * This function implements the API that's compatible with current
10096495d90SSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
10196495d90SSimon Glass  * GPIO driver. Returns 0 on success, negative value on error.
10296495d90SSimon Glass  */
10396495d90SSimon Glass int gpio_request(unsigned gpio, const char *label)
10496495d90SSimon Glass {
105b892d127SSimon Glass 	struct gpio_dev_priv *uc_priv;
10696495d90SSimon Glass 	unsigned int offset;
10754c5d08aSHeiko Schocher 	struct udevice *dev;
108b892d127SSimon Glass 	char *str;
10996495d90SSimon Glass 	int ret;
11096495d90SSimon Glass 
11196495d90SSimon Glass 	ret = gpio_to_device(gpio, &dev, &offset);
11296495d90SSimon Glass 	if (ret)
11396495d90SSimon Glass 		return ret;
11496495d90SSimon Glass 
115b892d127SSimon Glass 	uc_priv = dev->uclass_priv;
116b892d127SSimon Glass 	if (uc_priv->name[offset])
117b892d127SSimon Glass 		return -EBUSY;
118b892d127SSimon Glass 	str = strdup(label);
119b892d127SSimon Glass 	if (!str)
120b892d127SSimon Glass 		return -ENOMEM;
121b892d127SSimon Glass 	if (gpio_get_ops(dev)->request) {
122b892d127SSimon Glass 		ret = gpio_get_ops(dev)->request(dev, offset, label);
123b892d127SSimon Glass 		if (ret) {
124b892d127SSimon Glass 			free(str);
125b892d127SSimon Glass 			return ret;
126b892d127SSimon Glass 		}
127b892d127SSimon Glass 	}
128b892d127SSimon Glass 	uc_priv->name[offset] = str;
12996495d90SSimon Glass 
130b892d127SSimon Glass 	return 0;
13196495d90SSimon Glass }
13296495d90SSimon Glass 
13396495d90SSimon Glass /**
134*d44f597bSSimon Glass  * gpio_requestf() - [COMPAT] Request GPIO
135*d44f597bSSimon Glass  * @gpio:	GPIO number
136*d44f597bSSimon Glass  * @fmt:	Format string for the requested GPIO
137*d44f597bSSimon Glass  * @...:	Arguments for the printf() format string
138*d44f597bSSimon Glass  *
139*d44f597bSSimon Glass  * This function implements the API that's compatible with current
140*d44f597bSSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
141*d44f597bSSimon Glass  * GPIO driver. Returns 0 on success, negative value on error.
142*d44f597bSSimon Glass  */
143*d44f597bSSimon Glass int gpio_requestf(unsigned gpio, const char *fmt, ...)
144*d44f597bSSimon Glass {
145*d44f597bSSimon Glass 	va_list args;
146*d44f597bSSimon Glass 	char buf[40];
147*d44f597bSSimon Glass 
148*d44f597bSSimon Glass 	va_start(args, fmt);
149*d44f597bSSimon Glass 	vscnprintf(buf, sizeof(buf), fmt, args);
150*d44f597bSSimon Glass 	va_end(args);
151*d44f597bSSimon Glass 	return gpio_request(gpio, buf);
152*d44f597bSSimon Glass }
153*d44f597bSSimon Glass 
154*d44f597bSSimon Glass /**
15596495d90SSimon Glass  * gpio_free() - [COMPAT] Relinquish GPIO
15696495d90SSimon Glass  * gpio:	GPIO number
15796495d90SSimon Glass  *
15896495d90SSimon Glass  * This function implements the API that's compatible with current
15996495d90SSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
16096495d90SSimon Glass  * GPIO driver. Returns 0 on success, negative value on error.
16196495d90SSimon Glass  */
16296495d90SSimon Glass int gpio_free(unsigned gpio)
16396495d90SSimon Glass {
164b892d127SSimon Glass 	struct gpio_dev_priv *uc_priv;
16596495d90SSimon Glass 	unsigned int offset;
16654c5d08aSHeiko Schocher 	struct udevice *dev;
16796495d90SSimon Glass 	int ret;
16896495d90SSimon Glass 
16996495d90SSimon Glass 	ret = gpio_to_device(gpio, &dev, &offset);
17096495d90SSimon Glass 	if (ret)
17196495d90SSimon Glass 		return ret;
17296495d90SSimon Glass 
173b892d127SSimon Glass 	uc_priv = dev->uclass_priv;
174b892d127SSimon Glass 	if (!uc_priv->name[offset])
175b892d127SSimon Glass 		return -ENXIO;
176b892d127SSimon Glass 	if (gpio_get_ops(dev)->free) {
177b892d127SSimon Glass 		ret = gpio_get_ops(dev)->free(dev, offset);
178b892d127SSimon Glass 		if (ret)
179b892d127SSimon Glass 			return ret;
180b892d127SSimon Glass 	}
181b892d127SSimon Glass 
182b892d127SSimon Glass 	free(uc_priv->name[offset]);
183b892d127SSimon Glass 	uc_priv->name[offset] = NULL;
184b892d127SSimon Glass 
18596495d90SSimon Glass 	return 0;
186b892d127SSimon Glass }
187b892d127SSimon Glass 
188b892d127SSimon Glass static int check_reserved(struct udevice *dev, unsigned offset,
189b892d127SSimon Glass 			  const char *func)
190b892d127SSimon Glass {
191b892d127SSimon Glass 	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
192b892d127SSimon Glass 
193b892d127SSimon Glass 	if (!uc_priv->name[offset]) {
194b892d127SSimon Glass 		printf("%s: %s: error: gpio %s%d not reserved\n",
195b892d127SSimon Glass 		       dev->name, func,
196b892d127SSimon Glass 		       uc_priv->bank_name ? uc_priv->bank_name : "", offset);
197b892d127SSimon Glass 		return -EBUSY;
198b892d127SSimon Glass 	}
199b892d127SSimon Glass 
200b892d127SSimon Glass 	return 0;
20196495d90SSimon Glass }
20296495d90SSimon Glass 
20396495d90SSimon Glass /**
20496495d90SSimon Glass  * gpio_direction_input() - [COMPAT] Set GPIO direction to input
20596495d90SSimon Glass  * gpio:	GPIO number
20696495d90SSimon Glass  *
20796495d90SSimon Glass  * This function implements the API that's compatible with current
20896495d90SSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
20996495d90SSimon Glass  * GPIO driver. Returns 0 on success, negative value on error.
21096495d90SSimon Glass  */
21196495d90SSimon Glass int gpio_direction_input(unsigned gpio)
21296495d90SSimon Glass {
21396495d90SSimon Glass 	unsigned int offset;
21454c5d08aSHeiko Schocher 	struct udevice *dev;
21596495d90SSimon Glass 	int ret;
21696495d90SSimon Glass 
21796495d90SSimon Glass 	ret = gpio_to_device(gpio, &dev, &offset);
21896495d90SSimon Glass 	if (ret)
21996495d90SSimon Glass 		return ret;
220b892d127SSimon Glass 	ret = check_reserved(dev, offset, "dir_input");
22196495d90SSimon Glass 
222b892d127SSimon Glass 	return ret ? ret : gpio_get_ops(dev)->direction_input(dev, offset);
22396495d90SSimon Glass }
22496495d90SSimon Glass 
22596495d90SSimon Glass /**
22696495d90SSimon Glass  * gpio_direction_output() - [COMPAT] Set GPIO direction to output and set value
22796495d90SSimon Glass  * gpio:	GPIO number
22896495d90SSimon Glass  * value:	Logical value to be set on the GPIO pin
22996495d90SSimon Glass  *
23096495d90SSimon Glass  * This function implements the API that's compatible with current
23196495d90SSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
23296495d90SSimon Glass  * GPIO driver. Returns 0 on success, negative value on error.
23396495d90SSimon Glass  */
23496495d90SSimon Glass int gpio_direction_output(unsigned gpio, int value)
23596495d90SSimon Glass {
23696495d90SSimon Glass 	unsigned int offset;
23754c5d08aSHeiko Schocher 	struct udevice *dev;
23896495d90SSimon Glass 	int ret;
23996495d90SSimon Glass 
24096495d90SSimon Glass 	ret = gpio_to_device(gpio, &dev, &offset);
24196495d90SSimon Glass 	if (ret)
24296495d90SSimon Glass 		return ret;
243b892d127SSimon Glass 	ret = check_reserved(dev, offset, "dir_output");
24496495d90SSimon Glass 
245b892d127SSimon Glass 	return ret ? ret :
246b892d127SSimon Glass 		gpio_get_ops(dev)->direction_output(dev, offset, value);
24796495d90SSimon Glass }
24896495d90SSimon Glass 
24996495d90SSimon Glass /**
25096495d90SSimon Glass  * gpio_get_value() - [COMPAT] Sample GPIO pin and return it's value
25196495d90SSimon Glass  * gpio:	GPIO number
25296495d90SSimon Glass  *
25396495d90SSimon Glass  * This function implements the API that's compatible with current
25496495d90SSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
25596495d90SSimon Glass  * GPIO driver. Returns the value of the GPIO pin, or negative value
25696495d90SSimon Glass  * on error.
25796495d90SSimon Glass  */
25896495d90SSimon Glass int gpio_get_value(unsigned gpio)
25996495d90SSimon Glass {
26096495d90SSimon Glass 	unsigned int offset;
26154c5d08aSHeiko Schocher 	struct udevice *dev;
26296495d90SSimon Glass 	int ret;
26396495d90SSimon Glass 
26496495d90SSimon Glass 	ret = gpio_to_device(gpio, &dev, &offset);
26596495d90SSimon Glass 	if (ret)
26696495d90SSimon Glass 		return ret;
267b892d127SSimon Glass 	ret = check_reserved(dev, offset, "get_value");
26896495d90SSimon Glass 
269b892d127SSimon Glass 	return ret ? ret : gpio_get_ops(dev)->get_value(dev, offset);
27096495d90SSimon Glass }
27196495d90SSimon Glass 
27296495d90SSimon Glass /**
27396495d90SSimon Glass  * gpio_set_value() - [COMPAT] Configure logical value on GPIO pin
27496495d90SSimon Glass  * gpio:	GPIO number
27596495d90SSimon Glass  * value:	Logical value to be set on the GPIO pin.
27696495d90SSimon Glass  *
27796495d90SSimon Glass  * This function implements the API that's compatible with current
27896495d90SSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
27996495d90SSimon Glass  * GPIO driver. Returns 0 on success, negative value on error.
28096495d90SSimon Glass  */
28196495d90SSimon Glass int gpio_set_value(unsigned gpio, int value)
28296495d90SSimon Glass {
28396495d90SSimon Glass 	unsigned int offset;
28454c5d08aSHeiko Schocher 	struct udevice *dev;
28596495d90SSimon Glass 	int ret;
28696495d90SSimon Glass 
28796495d90SSimon Glass 	ret = gpio_to_device(gpio, &dev, &offset);
28896495d90SSimon Glass 	if (ret)
28996495d90SSimon Glass 		return ret;
290b892d127SSimon Glass 	ret = check_reserved(dev, offset, "set_value");
29196495d90SSimon Glass 
292b892d127SSimon Glass 	return ret ? ret : gpio_get_ops(dev)->set_value(dev, offset, value);
29396495d90SSimon Glass }
29496495d90SSimon Glass 
29554c5d08aSHeiko Schocher const char *gpio_get_bank_info(struct udevice *dev, int *bit_count)
29696495d90SSimon Glass {
29796495d90SSimon Glass 	struct gpio_dev_priv *priv;
29896495d90SSimon Glass 
29996495d90SSimon Glass 	/* Must be called on an active device */
30096495d90SSimon Glass 	priv = dev->uclass_priv;
30196495d90SSimon Glass 	assert(priv);
30296495d90SSimon Glass 
30396495d90SSimon Glass 	*bit_count = priv->gpio_count;
30496495d90SSimon Glass 	return priv->bank_name;
30596495d90SSimon Glass }
30696495d90SSimon Glass 
3076449a506SSimon Glass static const char * const gpio_function[GPIOF_COUNT] = {
3086449a506SSimon Glass 	"input",
3096449a506SSimon Glass 	"output",
3106449a506SSimon Glass 	"unused",
3116449a506SSimon Glass 	"unknown",
3126449a506SSimon Glass 	"func",
3136449a506SSimon Glass };
3146449a506SSimon Glass 
3156449a506SSimon Glass int get_function(struct udevice *dev, int offset, bool skip_unused,
3166449a506SSimon Glass 		 const char **namep)
3176449a506SSimon Glass {
3186449a506SSimon Glass 	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
3196449a506SSimon Glass 	struct dm_gpio_ops *ops = gpio_get_ops(dev);
3206449a506SSimon Glass 
3216449a506SSimon Glass 	BUILD_BUG_ON(GPIOF_COUNT != ARRAY_SIZE(gpio_function));
3226449a506SSimon Glass 	if (!device_active(dev))
3236449a506SSimon Glass 		return -ENODEV;
3246449a506SSimon Glass 	if (offset < 0 || offset >= uc_priv->gpio_count)
3256449a506SSimon Glass 		return -EINVAL;
3266449a506SSimon Glass 	if (namep)
3276449a506SSimon Glass 		*namep = uc_priv->name[offset];
3286449a506SSimon Glass 	if (skip_unused && !uc_priv->name[offset])
3296449a506SSimon Glass 		return GPIOF_UNUSED;
3306449a506SSimon Glass 	if (ops->get_function) {
3316449a506SSimon Glass 		int ret;
3326449a506SSimon Glass 
3336449a506SSimon Glass 		ret = ops->get_function(dev, offset);
3346449a506SSimon Glass 		if (ret < 0)
3356449a506SSimon Glass 			return ret;
3366449a506SSimon Glass 		if (ret >= ARRAY_SIZE(gpio_function))
3376449a506SSimon Glass 			return -ENODATA;
3386449a506SSimon Glass 		return ret;
3396449a506SSimon Glass 	}
3406449a506SSimon Glass 
3416449a506SSimon Glass 	return GPIOF_UNKNOWN;
3426449a506SSimon Glass }
3436449a506SSimon Glass 
3446449a506SSimon Glass int gpio_get_function(struct udevice *dev, int offset, const char **namep)
3456449a506SSimon Glass {
3466449a506SSimon Glass 	return get_function(dev, offset, true, namep);
3476449a506SSimon Glass }
3486449a506SSimon Glass 
3496449a506SSimon Glass int gpio_get_raw_function(struct udevice *dev, int offset, const char **namep)
3506449a506SSimon Glass {
3516449a506SSimon Glass 	return get_function(dev, offset, false, namep);
3526449a506SSimon Glass }
3536449a506SSimon Glass 
3540757535aSSimon Glass int gpio_get_status(struct udevice *dev, int offset, char *buf, int buffsize)
3550757535aSSimon Glass {
3560757535aSSimon Glass 	struct dm_gpio_ops *ops = gpio_get_ops(dev);
3570757535aSSimon Glass 	struct gpio_dev_priv *priv;
3580757535aSSimon Glass 	char *str = buf;
3590757535aSSimon Glass 	int func;
3600757535aSSimon Glass 	int ret;
3610757535aSSimon Glass 	int len;
3620757535aSSimon Glass 
3630757535aSSimon Glass 	BUILD_BUG_ON(GPIOF_COUNT != ARRAY_SIZE(gpio_function));
3640757535aSSimon Glass 
3650757535aSSimon Glass 	*buf = 0;
3660757535aSSimon Glass 	priv = dev->uclass_priv;
3670757535aSSimon Glass 	ret = gpio_get_raw_function(dev, offset, NULL);
3680757535aSSimon Glass 	if (ret < 0)
3690757535aSSimon Glass 		return ret;
3700757535aSSimon Glass 	func = ret;
3710757535aSSimon Glass 	len = snprintf(str, buffsize, "%s%d: %s",
3720757535aSSimon Glass 		       priv->bank_name ? priv->bank_name : "",
3730757535aSSimon Glass 		       offset, gpio_function[func]);
3740757535aSSimon Glass 	if (func == GPIOF_INPUT || func == GPIOF_OUTPUT ||
3750757535aSSimon Glass 	    func == GPIOF_UNUSED) {
3760757535aSSimon Glass 		const char *label;
3770757535aSSimon Glass 		bool used;
3780757535aSSimon Glass 
3790757535aSSimon Glass 		ret = ops->get_value(dev, offset);
3800757535aSSimon Glass 		if (ret < 0)
3810757535aSSimon Glass 			return ret;
3820757535aSSimon Glass 		used = gpio_get_function(dev, offset, &label) != GPIOF_UNUSED;
3830757535aSSimon Glass 		snprintf(str + len, buffsize - len, ": %d [%c]%s%s",
3840757535aSSimon Glass 			 ret,
3850757535aSSimon Glass 			 used ? 'x' : ' ',
3860757535aSSimon Glass 			 used ? " " : "",
3870757535aSSimon Glass 			 label ? label : "");
3880757535aSSimon Glass 	}
3890757535aSSimon Glass 
3900757535aSSimon Glass 	return 0;
3910757535aSSimon Glass }
3920757535aSSimon Glass 
39396495d90SSimon Glass /* We need to renumber the GPIOs when any driver is probed/removed */
394b892d127SSimon Glass static int gpio_renumber(struct udevice *removed_dev)
39596495d90SSimon Glass {
39696495d90SSimon Glass 	struct gpio_dev_priv *uc_priv;
39754c5d08aSHeiko Schocher 	struct udevice *dev;
39896495d90SSimon Glass 	struct uclass *uc;
39996495d90SSimon Glass 	unsigned base;
40096495d90SSimon Glass 	int ret;
40196495d90SSimon Glass 
40296495d90SSimon Glass 	ret = uclass_get(UCLASS_GPIO, &uc);
40396495d90SSimon Glass 	if (ret)
40496495d90SSimon Glass 		return ret;
40596495d90SSimon Glass 
40696495d90SSimon Glass 	/* Ensure that we have a base for each bank */
40796495d90SSimon Glass 	base = 0;
40896495d90SSimon Glass 	uclass_foreach_dev(dev, uc) {
409b892d127SSimon Glass 		if (device_active(dev) && dev != removed_dev) {
41096495d90SSimon Glass 			uc_priv = dev->uclass_priv;
41196495d90SSimon Glass 			uc_priv->gpio_base = base;
41296495d90SSimon Glass 			base += uc_priv->gpio_count;
41396495d90SSimon Glass 		}
41496495d90SSimon Glass 	}
41596495d90SSimon Glass 
41696495d90SSimon Glass 	return 0;
41796495d90SSimon Glass }
41896495d90SSimon Glass 
41954c5d08aSHeiko Schocher static int gpio_post_probe(struct udevice *dev)
42096495d90SSimon Glass {
421b892d127SSimon Glass 	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
422b892d127SSimon Glass 
423b892d127SSimon Glass 	uc_priv->name = calloc(uc_priv->gpio_count, sizeof(char *));
424b892d127SSimon Glass 	if (!uc_priv->name)
425b892d127SSimon Glass 		return -ENOMEM;
426b892d127SSimon Glass 
427b892d127SSimon Glass 	return gpio_renumber(NULL);
42896495d90SSimon Glass }
42996495d90SSimon Glass 
43054c5d08aSHeiko Schocher static int gpio_pre_remove(struct udevice *dev)
43196495d90SSimon Glass {
432b892d127SSimon Glass 	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
433b892d127SSimon Glass 	int i;
434b892d127SSimon Glass 
435b892d127SSimon Glass 	for (i = 0; i < uc_priv->gpio_count; i++) {
436b892d127SSimon Glass 		if (uc_priv->name[i])
437b892d127SSimon Glass 			free(uc_priv->name[i]);
438b892d127SSimon Glass 	}
439b892d127SSimon Glass 	free(uc_priv->name);
440b892d127SSimon Glass 
441b892d127SSimon Glass 	return gpio_renumber(dev);
44296495d90SSimon Glass }
44396495d90SSimon Glass 
44496495d90SSimon Glass UCLASS_DRIVER(gpio) = {
44596495d90SSimon Glass 	.id		= UCLASS_GPIO,
44696495d90SSimon Glass 	.name		= "gpio",
44796495d90SSimon Glass 	.post_probe	= gpio_post_probe,
44896495d90SSimon Glass 	.pre_remove	= gpio_pre_remove,
44996495d90SSimon Glass 	.per_device_auto_alloc_size = sizeof(struct gpio_dev_priv),
45096495d90SSimon Glass };
451