xref: /openbmc/u-boot/drivers/gpio/gpio-uclass.c (revision 54c5d08a09e631f88738db54c75395c6457c2157)
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>
1096495d90SSimon Glass #include <asm/gpio.h>
1196495d90SSimon Glass 
1296495d90SSimon Glass /**
1396495d90SSimon Glass  * gpio_to_device() - Convert global GPIO number to device, number
1496495d90SSimon Glass  * gpio:	The numeric representation of the GPIO
1596495d90SSimon Glass  *
1696495d90SSimon Glass  * Convert the GPIO number to an entry in the list of GPIOs
1796495d90SSimon Glass  * or GPIO blocks registered with the GPIO controller. Returns
1896495d90SSimon Glass  * entry on success, NULL on error.
1996495d90SSimon Glass  */
20*54c5d08aSHeiko Schocher static int gpio_to_device(unsigned int gpio, struct udevice **devp,
2196495d90SSimon Glass 			  unsigned int *offset)
2296495d90SSimon Glass {
2396495d90SSimon Glass 	struct gpio_dev_priv *uc_priv;
24*54c5d08aSHeiko Schocher 	struct udevice *dev;
2596495d90SSimon Glass 	int ret;
2696495d90SSimon Glass 
2796495d90SSimon Glass 	for (ret = uclass_first_device(UCLASS_GPIO, &dev);
2896495d90SSimon Glass 	     dev;
2996495d90SSimon Glass 	     ret = uclass_next_device(&dev)) {
3096495d90SSimon Glass 		uc_priv = dev->uclass_priv;
3196495d90SSimon Glass 		if (gpio >= uc_priv->gpio_base &&
3296495d90SSimon Glass 		    gpio < uc_priv->gpio_base + uc_priv->gpio_count) {
3396495d90SSimon Glass 			*devp = dev;
3496495d90SSimon Glass 			*offset = gpio - uc_priv->gpio_base;
3596495d90SSimon Glass 			return 0;
3696495d90SSimon Glass 		}
3796495d90SSimon Glass 	}
3896495d90SSimon Glass 
3996495d90SSimon Glass 	/* No such GPIO */
4096495d90SSimon Glass 	return ret ? ret : -EINVAL;
4196495d90SSimon Glass }
4296495d90SSimon Glass 
43*54c5d08aSHeiko Schocher int gpio_lookup_name(const char *name, struct udevice **devp,
4496495d90SSimon Glass 		     unsigned int *offsetp, unsigned int *gpiop)
4596495d90SSimon Glass {
4696495d90SSimon Glass 	struct gpio_dev_priv *uc_priv;
47*54c5d08aSHeiko Schocher 	struct udevice *dev;
4896495d90SSimon Glass 	int ret;
4996495d90SSimon Glass 
5096495d90SSimon Glass 	if (devp)
5196495d90SSimon Glass 		*devp = NULL;
5296495d90SSimon Glass 	for (ret = uclass_first_device(UCLASS_GPIO, &dev);
5396495d90SSimon Glass 	     dev;
5496495d90SSimon Glass 	     ret = uclass_next_device(&dev)) {
5596495d90SSimon Glass 		ulong offset;
5696495d90SSimon Glass 		int len;
5796495d90SSimon Glass 
5896495d90SSimon Glass 		uc_priv = dev->uclass_priv;
5996495d90SSimon Glass 		len = uc_priv->bank_name ? strlen(uc_priv->bank_name) : 0;
6096495d90SSimon Glass 
6196495d90SSimon Glass 		if (!strncmp(name, uc_priv->bank_name, len)) {
6296495d90SSimon Glass 			if (strict_strtoul(name + len, 10, &offset))
6396495d90SSimon Glass 				continue;
6496495d90SSimon Glass 			if (devp)
6596495d90SSimon Glass 				*devp = dev;
6696495d90SSimon Glass 			if (offsetp)
6796495d90SSimon Glass 				*offsetp = offset;
6896495d90SSimon Glass 			if (gpiop)
6996495d90SSimon Glass 				*gpiop = uc_priv->gpio_base + offset;
7096495d90SSimon Glass 			return 0;
7196495d90SSimon Glass 		}
7296495d90SSimon Glass 	}
7396495d90SSimon Glass 
7496495d90SSimon Glass 	return ret ? ret : -EINVAL;
7596495d90SSimon Glass }
7696495d90SSimon Glass 
7796495d90SSimon Glass /**
7896495d90SSimon Glass  * gpio_request() - [COMPAT] Request GPIO
7996495d90SSimon Glass  * gpio:	GPIO number
8096495d90SSimon Glass  * label:	Name for the requested GPIO
8196495d90SSimon Glass  *
8296495d90SSimon Glass  * This function implements the API that's compatible with current
8396495d90SSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
8496495d90SSimon Glass  * GPIO driver. Returns 0 on success, negative value on error.
8596495d90SSimon Glass  */
8696495d90SSimon Glass int gpio_request(unsigned gpio, const char *label)
8796495d90SSimon Glass {
8896495d90SSimon Glass 	unsigned int offset;
89*54c5d08aSHeiko Schocher 	struct udevice *dev;
9096495d90SSimon Glass 	int ret;
9196495d90SSimon Glass 
9296495d90SSimon Glass 	ret = gpio_to_device(gpio, &dev, &offset);
9396495d90SSimon Glass 	if (ret)
9496495d90SSimon Glass 		return ret;
9596495d90SSimon Glass 
9696495d90SSimon Glass 	if (!gpio_get_ops(dev)->request)
9796495d90SSimon Glass 		return 0;
9896495d90SSimon Glass 
9996495d90SSimon Glass 	return gpio_get_ops(dev)->request(dev, offset, label);
10096495d90SSimon Glass }
10196495d90SSimon Glass 
10296495d90SSimon Glass /**
10396495d90SSimon Glass  * gpio_free() - [COMPAT] Relinquish GPIO
10496495d90SSimon Glass  * gpio:	GPIO number
10596495d90SSimon Glass  *
10696495d90SSimon Glass  * This function implements the API that's compatible with current
10796495d90SSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
10896495d90SSimon Glass  * GPIO driver. Returns 0 on success, negative value on error.
10996495d90SSimon Glass  */
11096495d90SSimon Glass int gpio_free(unsigned gpio)
11196495d90SSimon Glass {
11296495d90SSimon Glass 	unsigned int offset;
113*54c5d08aSHeiko Schocher 	struct udevice *dev;
11496495d90SSimon Glass 	int ret;
11596495d90SSimon Glass 
11696495d90SSimon Glass 	ret = gpio_to_device(gpio, &dev, &offset);
11796495d90SSimon Glass 	if (ret)
11896495d90SSimon Glass 		return ret;
11996495d90SSimon Glass 
12096495d90SSimon Glass 	if (!gpio_get_ops(dev)->free)
12196495d90SSimon Glass 		return 0;
12296495d90SSimon Glass 	return gpio_get_ops(dev)->free(dev, offset);
12396495d90SSimon Glass }
12496495d90SSimon Glass 
12596495d90SSimon Glass /**
12696495d90SSimon Glass  * gpio_direction_input() - [COMPAT] Set GPIO direction to input
12796495d90SSimon Glass  * gpio:	GPIO number
12896495d90SSimon Glass  *
12996495d90SSimon Glass  * This function implements the API that's compatible with current
13096495d90SSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
13196495d90SSimon Glass  * GPIO driver. Returns 0 on success, negative value on error.
13296495d90SSimon Glass  */
13396495d90SSimon Glass int gpio_direction_input(unsigned gpio)
13496495d90SSimon Glass {
13596495d90SSimon Glass 	unsigned int offset;
136*54c5d08aSHeiko Schocher 	struct udevice *dev;
13796495d90SSimon Glass 	int ret;
13896495d90SSimon Glass 
13996495d90SSimon Glass 	ret = gpio_to_device(gpio, &dev, &offset);
14096495d90SSimon Glass 	if (ret)
14196495d90SSimon Glass 		return ret;
14296495d90SSimon Glass 
14396495d90SSimon Glass 	return gpio_get_ops(dev)->direction_input(dev, offset);
14496495d90SSimon Glass }
14596495d90SSimon Glass 
14696495d90SSimon Glass /**
14796495d90SSimon Glass  * gpio_direction_output() - [COMPAT] Set GPIO direction to output and set value
14896495d90SSimon Glass  * gpio:	GPIO number
14996495d90SSimon Glass  * value:	Logical value to be set on the GPIO pin
15096495d90SSimon Glass  *
15196495d90SSimon Glass  * This function implements the API that's compatible with current
15296495d90SSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
15396495d90SSimon Glass  * GPIO driver. Returns 0 on success, negative value on error.
15496495d90SSimon Glass  */
15596495d90SSimon Glass int gpio_direction_output(unsigned gpio, int value)
15696495d90SSimon Glass {
15796495d90SSimon Glass 	unsigned int offset;
158*54c5d08aSHeiko Schocher 	struct udevice *dev;
15996495d90SSimon Glass 	int ret;
16096495d90SSimon Glass 
16196495d90SSimon Glass 	ret = gpio_to_device(gpio, &dev, &offset);
16296495d90SSimon Glass 	if (ret)
16396495d90SSimon Glass 		return ret;
16496495d90SSimon Glass 
16596495d90SSimon Glass 	return gpio_get_ops(dev)->direction_output(dev, offset, value);
16696495d90SSimon Glass }
16796495d90SSimon Glass 
16896495d90SSimon Glass /**
16996495d90SSimon Glass  * gpio_get_value() - [COMPAT] Sample GPIO pin and return it's value
17096495d90SSimon Glass  * gpio:	GPIO number
17196495d90SSimon Glass  *
17296495d90SSimon Glass  * This function implements the API that's compatible with current
17396495d90SSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
17496495d90SSimon Glass  * GPIO driver. Returns the value of the GPIO pin, or negative value
17596495d90SSimon Glass  * on error.
17696495d90SSimon Glass  */
17796495d90SSimon Glass int gpio_get_value(unsigned gpio)
17896495d90SSimon Glass {
17996495d90SSimon Glass 	unsigned int offset;
180*54c5d08aSHeiko Schocher 	struct udevice *dev;
18196495d90SSimon Glass 	int ret;
18296495d90SSimon Glass 
18396495d90SSimon Glass 	ret = gpio_to_device(gpio, &dev, &offset);
18496495d90SSimon Glass 	if (ret)
18596495d90SSimon Glass 		return ret;
18696495d90SSimon Glass 
18796495d90SSimon Glass 	return gpio_get_ops(dev)->get_value(dev, offset);
18896495d90SSimon Glass }
18996495d90SSimon Glass 
19096495d90SSimon Glass /**
19196495d90SSimon Glass  * gpio_set_value() - [COMPAT] Configure logical value on GPIO pin
19296495d90SSimon Glass  * gpio:	GPIO number
19396495d90SSimon Glass  * value:	Logical value to be set on the GPIO pin.
19496495d90SSimon Glass  *
19596495d90SSimon Glass  * This function implements the API that's compatible with current
19696495d90SSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
19796495d90SSimon Glass  * GPIO driver. Returns 0 on success, negative value on error.
19896495d90SSimon Glass  */
19996495d90SSimon Glass int gpio_set_value(unsigned gpio, int value)
20096495d90SSimon Glass {
20196495d90SSimon Glass 	unsigned int offset;
202*54c5d08aSHeiko Schocher 	struct udevice *dev;
20396495d90SSimon Glass 	int ret;
20496495d90SSimon Glass 
20596495d90SSimon Glass 	ret = gpio_to_device(gpio, &dev, &offset);
20696495d90SSimon Glass 	if (ret)
20796495d90SSimon Glass 		return ret;
20896495d90SSimon Glass 
20996495d90SSimon Glass 	return gpio_get_ops(dev)->set_value(dev, offset, value);
21096495d90SSimon Glass }
21196495d90SSimon Glass 
212*54c5d08aSHeiko Schocher const char *gpio_get_bank_info(struct udevice *dev, int *bit_count)
21396495d90SSimon Glass {
21496495d90SSimon Glass 	struct gpio_dev_priv *priv;
21596495d90SSimon Glass 
21696495d90SSimon Glass 	/* Must be called on an active device */
21796495d90SSimon Glass 	priv = dev->uclass_priv;
21896495d90SSimon Glass 	assert(priv);
21996495d90SSimon Glass 
22096495d90SSimon Glass 	*bit_count = priv->gpio_count;
22196495d90SSimon Glass 	return priv->bank_name;
22296495d90SSimon Glass }
22396495d90SSimon Glass 
22496495d90SSimon Glass /* We need to renumber the GPIOs when any driver is probed/removed */
22596495d90SSimon Glass static int gpio_renumber(void)
22696495d90SSimon Glass {
22796495d90SSimon Glass 	struct gpio_dev_priv *uc_priv;
228*54c5d08aSHeiko Schocher 	struct udevice *dev;
22996495d90SSimon Glass 	struct uclass *uc;
23096495d90SSimon Glass 	unsigned base;
23196495d90SSimon Glass 	int ret;
23296495d90SSimon Glass 
23396495d90SSimon Glass 	ret = uclass_get(UCLASS_GPIO, &uc);
23496495d90SSimon Glass 	if (ret)
23596495d90SSimon Glass 		return ret;
23696495d90SSimon Glass 
23796495d90SSimon Glass 	/* Ensure that we have a base for each bank */
23896495d90SSimon Glass 	base = 0;
23996495d90SSimon Glass 	uclass_foreach_dev(dev, uc) {
24096495d90SSimon Glass 		if (device_active(dev)) {
24196495d90SSimon Glass 			uc_priv = dev->uclass_priv;
24296495d90SSimon Glass 			uc_priv->gpio_base = base;
24396495d90SSimon Glass 			base += uc_priv->gpio_count;
24496495d90SSimon Glass 		}
24596495d90SSimon Glass 	}
24696495d90SSimon Glass 
24796495d90SSimon Glass 	return 0;
24896495d90SSimon Glass }
24996495d90SSimon Glass 
250*54c5d08aSHeiko Schocher static int gpio_post_probe(struct udevice *dev)
25196495d90SSimon Glass {
25296495d90SSimon Glass 	return gpio_renumber();
25396495d90SSimon Glass }
25496495d90SSimon Glass 
255*54c5d08aSHeiko Schocher static int gpio_pre_remove(struct udevice *dev)
25696495d90SSimon Glass {
25796495d90SSimon Glass 	return gpio_renumber();
25896495d90SSimon Glass }
25996495d90SSimon Glass 
26096495d90SSimon Glass UCLASS_DRIVER(gpio) = {
26196495d90SSimon Glass 	.id		= UCLASS_GPIO,
26296495d90SSimon Glass 	.name		= "gpio",
26396495d90SSimon Glass 	.post_probe	= gpio_post_probe,
26496495d90SSimon Glass 	.pre_remove	= gpio_pre_remove,
26596495d90SSimon Glass 	.per_device_auto_alloc_size = sizeof(struct gpio_dev_priv),
26696495d90SSimon Glass };
267