xref: /openbmc/u-boot/drivers/gpio/gpio-uclass.c (revision fe1ef503381c4c03c059de3324271ce21cae3078)
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>
11*fe1ef503SSimon Glass #include <linux/ctype.h>
1296495d90SSimon Glass 
1396495d90SSimon Glass /**
1496495d90SSimon Glass  * gpio_to_device() - Convert global GPIO number to device, number
1596495d90SSimon Glass  * gpio:	The numeric representation of the GPIO
1696495d90SSimon Glass  *
1796495d90SSimon Glass  * Convert the GPIO number to an entry in the list of GPIOs
1896495d90SSimon Glass  * or GPIO blocks registered with the GPIO controller. Returns
1996495d90SSimon Glass  * entry on success, NULL on error.
2096495d90SSimon Glass  */
2154c5d08aSHeiko Schocher static int gpio_to_device(unsigned int gpio, struct udevice **devp,
2296495d90SSimon Glass 			  unsigned int *offset)
2396495d90SSimon Glass {
2496495d90SSimon Glass 	struct gpio_dev_priv *uc_priv;
2554c5d08aSHeiko Schocher 	struct udevice *dev;
2696495d90SSimon Glass 	int ret;
2796495d90SSimon Glass 
2896495d90SSimon Glass 	for (ret = uclass_first_device(UCLASS_GPIO, &dev);
2996495d90SSimon Glass 	     dev;
3096495d90SSimon Glass 	     ret = uclass_next_device(&dev)) {
3196495d90SSimon Glass 		uc_priv = dev->uclass_priv;
3296495d90SSimon Glass 		if (gpio >= uc_priv->gpio_base &&
3396495d90SSimon Glass 		    gpio < uc_priv->gpio_base + uc_priv->gpio_count) {
3496495d90SSimon Glass 			*devp = dev;
3596495d90SSimon Glass 			*offset = gpio - uc_priv->gpio_base;
3696495d90SSimon Glass 			return 0;
3796495d90SSimon Glass 		}
3896495d90SSimon Glass 	}
3996495d90SSimon Glass 
4096495d90SSimon Glass 	/* No such GPIO */
4196495d90SSimon Glass 	return ret ? ret : -EINVAL;
4296495d90SSimon Glass }
4396495d90SSimon Glass 
4454c5d08aSHeiko Schocher int gpio_lookup_name(const char *name, struct udevice **devp,
4596495d90SSimon Glass 		     unsigned int *offsetp, unsigned int *gpiop)
4696495d90SSimon Glass {
47*fe1ef503SSimon Glass 	struct gpio_dev_priv *uc_priv = NULL;
4854c5d08aSHeiko Schocher 	struct udevice *dev;
49*fe1ef503SSimon Glass 	ulong offset;
50*fe1ef503SSimon Glass 	int numeric;
5196495d90SSimon Glass 	int ret;
5296495d90SSimon Glass 
5396495d90SSimon Glass 	if (devp)
5496495d90SSimon Glass 		*devp = NULL;
55*fe1ef503SSimon Glass 	numeric = isdigit(*name) ? simple_strtoul(name, NULL, 10) : -1;
5696495d90SSimon Glass 	for (ret = uclass_first_device(UCLASS_GPIO, &dev);
5796495d90SSimon Glass 	     dev;
5896495d90SSimon Glass 	     ret = uclass_next_device(&dev)) {
5996495d90SSimon Glass 		int len;
6096495d90SSimon Glass 
6196495d90SSimon Glass 		uc_priv = dev->uclass_priv;
62*fe1ef503SSimon Glass 		if (numeric != -1) {
63*fe1ef503SSimon Glass 			offset = numeric - uc_priv->gpio_base;
64*fe1ef503SSimon Glass 			/* Allow GPIOs to be numbered from 0 */
65*fe1ef503SSimon Glass 			if (offset >= 0 && offset < uc_priv->gpio_count)
66*fe1ef503SSimon Glass 				break;
67*fe1ef503SSimon Glass 		}
68*fe1ef503SSimon Glass 
6996495d90SSimon Glass 		len = uc_priv->bank_name ? strlen(uc_priv->bank_name) : 0;
7096495d90SSimon Glass 
71939cda5bSSimon Glass 		if (!strncasecmp(name, uc_priv->bank_name, len)) {
72*fe1ef503SSimon Glass 			if (!strict_strtoul(name + len, 10, &offset))
73*fe1ef503SSimon Glass 				break;
74*fe1ef503SSimon Glass 		}
75*fe1ef503SSimon Glass 	}
76*fe1ef503SSimon Glass 
77*fe1ef503SSimon Glass 	if (!dev)
78*fe1ef503SSimon Glass 		return ret ? ret : -EINVAL;
79*fe1ef503SSimon Glass 
8096495d90SSimon Glass 	if (devp)
8196495d90SSimon Glass 		*devp = dev;
8296495d90SSimon Glass 	if (offsetp)
8396495d90SSimon Glass 		*offsetp = offset;
8496495d90SSimon Glass 	if (gpiop)
8596495d90SSimon Glass 		*gpiop = uc_priv->gpio_base + offset;
8696495d90SSimon Glass 
87*fe1ef503SSimon Glass 	return 0;
8896495d90SSimon Glass }
8996495d90SSimon Glass 
9096495d90SSimon Glass /**
9196495d90SSimon Glass  * gpio_request() - [COMPAT] Request GPIO
9296495d90SSimon Glass  * gpio:	GPIO number
9396495d90SSimon Glass  * label:	Name for the requested GPIO
9496495d90SSimon Glass  *
9596495d90SSimon Glass  * This function implements the API that's compatible with current
9696495d90SSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
9796495d90SSimon Glass  * GPIO driver. Returns 0 on success, negative value on error.
9896495d90SSimon Glass  */
9996495d90SSimon Glass int gpio_request(unsigned gpio, const char *label)
10096495d90SSimon Glass {
10196495d90SSimon Glass 	unsigned int offset;
10254c5d08aSHeiko Schocher 	struct udevice *dev;
10396495d90SSimon Glass 	int ret;
10496495d90SSimon Glass 
10596495d90SSimon Glass 	ret = gpio_to_device(gpio, &dev, &offset);
10696495d90SSimon Glass 	if (ret)
10796495d90SSimon Glass 		return ret;
10896495d90SSimon Glass 
10996495d90SSimon Glass 	if (!gpio_get_ops(dev)->request)
11096495d90SSimon Glass 		return 0;
11196495d90SSimon Glass 
11296495d90SSimon Glass 	return gpio_get_ops(dev)->request(dev, offset, label);
11396495d90SSimon Glass }
11496495d90SSimon Glass 
11596495d90SSimon Glass /**
11696495d90SSimon Glass  * gpio_free() - [COMPAT] Relinquish GPIO
11796495d90SSimon Glass  * gpio:	GPIO number
11896495d90SSimon Glass  *
11996495d90SSimon Glass  * This function implements the API that's compatible with current
12096495d90SSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
12196495d90SSimon Glass  * GPIO driver. Returns 0 on success, negative value on error.
12296495d90SSimon Glass  */
12396495d90SSimon Glass int gpio_free(unsigned gpio)
12496495d90SSimon Glass {
12596495d90SSimon Glass 	unsigned int offset;
12654c5d08aSHeiko Schocher 	struct udevice *dev;
12796495d90SSimon Glass 	int ret;
12896495d90SSimon Glass 
12996495d90SSimon Glass 	ret = gpio_to_device(gpio, &dev, &offset);
13096495d90SSimon Glass 	if (ret)
13196495d90SSimon Glass 		return ret;
13296495d90SSimon Glass 
13396495d90SSimon Glass 	if (!gpio_get_ops(dev)->free)
13496495d90SSimon Glass 		return 0;
13596495d90SSimon Glass 	return gpio_get_ops(dev)->free(dev, offset);
13696495d90SSimon Glass }
13796495d90SSimon Glass 
13896495d90SSimon Glass /**
13996495d90SSimon Glass  * gpio_direction_input() - [COMPAT] Set GPIO direction to input
14096495d90SSimon Glass  * gpio:	GPIO number
14196495d90SSimon Glass  *
14296495d90SSimon Glass  * This function implements the API that's compatible with current
14396495d90SSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
14496495d90SSimon Glass  * GPIO driver. Returns 0 on success, negative value on error.
14596495d90SSimon Glass  */
14696495d90SSimon Glass int gpio_direction_input(unsigned gpio)
14796495d90SSimon Glass {
14896495d90SSimon Glass 	unsigned int offset;
14954c5d08aSHeiko Schocher 	struct udevice *dev;
15096495d90SSimon Glass 	int ret;
15196495d90SSimon Glass 
15296495d90SSimon Glass 	ret = gpio_to_device(gpio, &dev, &offset);
15396495d90SSimon Glass 	if (ret)
15496495d90SSimon Glass 		return ret;
15596495d90SSimon Glass 
15696495d90SSimon Glass 	return gpio_get_ops(dev)->direction_input(dev, offset);
15796495d90SSimon Glass }
15896495d90SSimon Glass 
15996495d90SSimon Glass /**
16096495d90SSimon Glass  * gpio_direction_output() - [COMPAT] Set GPIO direction to output and set value
16196495d90SSimon Glass  * gpio:	GPIO number
16296495d90SSimon Glass  * value:	Logical value to be set on the GPIO pin
16396495d90SSimon Glass  *
16496495d90SSimon Glass  * This function implements the API that's compatible with current
16596495d90SSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
16696495d90SSimon Glass  * GPIO driver. Returns 0 on success, negative value on error.
16796495d90SSimon Glass  */
16896495d90SSimon Glass int gpio_direction_output(unsigned gpio, int value)
16996495d90SSimon Glass {
17096495d90SSimon Glass 	unsigned int offset;
17154c5d08aSHeiko Schocher 	struct udevice *dev;
17296495d90SSimon Glass 	int ret;
17396495d90SSimon Glass 
17496495d90SSimon Glass 	ret = gpio_to_device(gpio, &dev, &offset);
17596495d90SSimon Glass 	if (ret)
17696495d90SSimon Glass 		return ret;
17796495d90SSimon Glass 
17896495d90SSimon Glass 	return gpio_get_ops(dev)->direction_output(dev, offset, value);
17996495d90SSimon Glass }
18096495d90SSimon Glass 
18196495d90SSimon Glass /**
18296495d90SSimon Glass  * gpio_get_value() - [COMPAT] Sample GPIO pin and return it's value
18396495d90SSimon Glass  * gpio:	GPIO number
18496495d90SSimon Glass  *
18596495d90SSimon Glass  * This function implements the API that's compatible with current
18696495d90SSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
18796495d90SSimon Glass  * GPIO driver. Returns the value of the GPIO pin, or negative value
18896495d90SSimon Glass  * on error.
18996495d90SSimon Glass  */
19096495d90SSimon Glass int gpio_get_value(unsigned gpio)
19196495d90SSimon Glass {
19296495d90SSimon Glass 	unsigned int offset;
19354c5d08aSHeiko Schocher 	struct udevice *dev;
19496495d90SSimon Glass 	int ret;
19596495d90SSimon Glass 
19696495d90SSimon Glass 	ret = gpio_to_device(gpio, &dev, &offset);
19796495d90SSimon Glass 	if (ret)
19896495d90SSimon Glass 		return ret;
19996495d90SSimon Glass 
20096495d90SSimon Glass 	return gpio_get_ops(dev)->get_value(dev, offset);
20196495d90SSimon Glass }
20296495d90SSimon Glass 
20396495d90SSimon Glass /**
20496495d90SSimon Glass  * gpio_set_value() - [COMPAT] Configure logical value on GPIO pin
20596495d90SSimon Glass  * gpio:	GPIO number
20696495d90SSimon Glass  * value:	Logical value to be set on the GPIO pin.
20796495d90SSimon Glass  *
20896495d90SSimon Glass  * This function implements the API that's compatible with current
20996495d90SSimon Glass  * GPIO API used in U-Boot. The request is forwarded to particular
21096495d90SSimon Glass  * GPIO driver. Returns 0 on success, negative value on error.
21196495d90SSimon Glass  */
21296495d90SSimon Glass int gpio_set_value(unsigned gpio, int value)
21396495d90SSimon Glass {
21496495d90SSimon Glass 	unsigned int offset;
21554c5d08aSHeiko Schocher 	struct udevice *dev;
21696495d90SSimon Glass 	int ret;
21796495d90SSimon Glass 
21896495d90SSimon Glass 	ret = gpio_to_device(gpio, &dev, &offset);
21996495d90SSimon Glass 	if (ret)
22096495d90SSimon Glass 		return ret;
22196495d90SSimon Glass 
22296495d90SSimon Glass 	return gpio_get_ops(dev)->set_value(dev, offset, value);
22396495d90SSimon Glass }
22496495d90SSimon Glass 
22554c5d08aSHeiko Schocher const char *gpio_get_bank_info(struct udevice *dev, int *bit_count)
22696495d90SSimon Glass {
22796495d90SSimon Glass 	struct gpio_dev_priv *priv;
22896495d90SSimon Glass 
22996495d90SSimon Glass 	/* Must be called on an active device */
23096495d90SSimon Glass 	priv = dev->uclass_priv;
23196495d90SSimon Glass 	assert(priv);
23296495d90SSimon Glass 
23396495d90SSimon Glass 	*bit_count = priv->gpio_count;
23496495d90SSimon Glass 	return priv->bank_name;
23596495d90SSimon Glass }
23696495d90SSimon Glass 
23796495d90SSimon Glass /* We need to renumber the GPIOs when any driver is probed/removed */
23896495d90SSimon Glass static int gpio_renumber(void)
23996495d90SSimon Glass {
24096495d90SSimon Glass 	struct gpio_dev_priv *uc_priv;
24154c5d08aSHeiko Schocher 	struct udevice *dev;
24296495d90SSimon Glass 	struct uclass *uc;
24396495d90SSimon Glass 	unsigned base;
24496495d90SSimon Glass 	int ret;
24596495d90SSimon Glass 
24696495d90SSimon Glass 	ret = uclass_get(UCLASS_GPIO, &uc);
24796495d90SSimon Glass 	if (ret)
24896495d90SSimon Glass 		return ret;
24996495d90SSimon Glass 
25096495d90SSimon Glass 	/* Ensure that we have a base for each bank */
25196495d90SSimon Glass 	base = 0;
25296495d90SSimon Glass 	uclass_foreach_dev(dev, uc) {
25396495d90SSimon Glass 		if (device_active(dev)) {
25496495d90SSimon Glass 			uc_priv = dev->uclass_priv;
25596495d90SSimon Glass 			uc_priv->gpio_base = base;
25696495d90SSimon Glass 			base += uc_priv->gpio_count;
25796495d90SSimon Glass 		}
25896495d90SSimon Glass 	}
25996495d90SSimon Glass 
26096495d90SSimon Glass 	return 0;
26196495d90SSimon Glass }
26296495d90SSimon Glass 
26354c5d08aSHeiko Schocher static int gpio_post_probe(struct udevice *dev)
26496495d90SSimon Glass {
26596495d90SSimon Glass 	return gpio_renumber();
26696495d90SSimon Glass }
26796495d90SSimon Glass 
26854c5d08aSHeiko Schocher static int gpio_pre_remove(struct udevice *dev)
26996495d90SSimon Glass {
27096495d90SSimon Glass 	return gpio_renumber();
27196495d90SSimon Glass }
27296495d90SSimon Glass 
27396495d90SSimon Glass UCLASS_DRIVER(gpio) = {
27496495d90SSimon Glass 	.id		= UCLASS_GPIO,
27596495d90SSimon Glass 	.name		= "gpio",
27696495d90SSimon Glass 	.post_probe	= gpio_post_probe,
27796495d90SSimon Glass 	.pre_remove	= gpio_pre_remove,
27896495d90SSimon Glass 	.per_device_auto_alloc_size = sizeof(struct gpio_dev_priv),
27996495d90SSimon Glass };
280