183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
296495d90SSimon Glass /*
396495d90SSimon Glass * Copyright (c) 2013 Google, Inc
496495d90SSimon Glass */
596495d90SSimon Glass
696495d90SSimon Glass #include <common.h>
796495d90SSimon Glass #include <dm.h>
804c095b2SHeiko Schocher #include <dm/device-internal.h>
904c095b2SHeiko Schocher #include <dm/lists.h>
1004c095b2SHeiko Schocher #include <dm/uclass-internal.h>
116c880b77SEric Nelson #include <dt-bindings/gpio/gpio.h>
1296495d90SSimon Glass #include <errno.h>
130dac4d51SSimon Glass #include <fdtdec.h>
14b892d127SSimon Glass #include <malloc.h>
1596495d90SSimon Glass #include <asm/gpio.h>
1684b8bf6dSMasahiro Yamada #include <linux/bug.h>
17fe1ef503SSimon Glass #include <linux/ctype.h>
1896495d90SSimon Glass
193669e0e7SSimon Glass DECLARE_GLOBAL_DATA_PTR;
203669e0e7SSimon Glass
2196495d90SSimon Glass /**
2296495d90SSimon Glass * gpio_to_device() - Convert global GPIO number to device, number
2396495d90SSimon Glass *
2496495d90SSimon Glass * Convert the GPIO number to an entry in the list of GPIOs
2596495d90SSimon Glass * or GPIO blocks registered with the GPIO controller. Returns
2696495d90SSimon Glass * entry on success, NULL on error.
27ae7123f8SSimon Glass *
28ae7123f8SSimon Glass * @gpio: The numeric representation of the GPIO
29ae7123f8SSimon Glass * @desc: Returns description (desc->flags will always be 0)
30ae7123f8SSimon Glass * @return 0 if found, -ENOENT if not found
3196495d90SSimon Glass */
gpio_to_device(unsigned int gpio,struct gpio_desc * desc)32ae7123f8SSimon Glass static int gpio_to_device(unsigned int gpio, struct gpio_desc *desc)
3396495d90SSimon Glass {
3496495d90SSimon Glass struct gpio_dev_priv *uc_priv;
3554c5d08aSHeiko Schocher struct udevice *dev;
3696495d90SSimon Glass int ret;
3796495d90SSimon Glass
3896495d90SSimon Glass for (ret = uclass_first_device(UCLASS_GPIO, &dev);
3996495d90SSimon Glass dev;
4096495d90SSimon Glass ret = uclass_next_device(&dev)) {
41e564f054SSimon Glass uc_priv = dev_get_uclass_priv(dev);
4296495d90SSimon Glass if (gpio >= uc_priv->gpio_base &&
4396495d90SSimon Glass gpio < uc_priv->gpio_base + uc_priv->gpio_count) {
44ae7123f8SSimon Glass desc->dev = dev;
45ae7123f8SSimon Glass desc->offset = gpio - uc_priv->gpio_base;
46ae7123f8SSimon Glass desc->flags = 0;
4796495d90SSimon Glass return 0;
4896495d90SSimon Glass }
4996495d90SSimon Glass }
5096495d90SSimon Glass
5196495d90SSimon Glass /* No such GPIO */
52ae7123f8SSimon Glass return ret ? ret : -ENOENT;
5396495d90SSimon Glass }
5496495d90SSimon Glass
dm_gpio_lookup_name(const char * name,struct gpio_desc * desc)5532ec1598SSimon Glass int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc)
5696495d90SSimon Glass {
57fe1ef503SSimon Glass struct gpio_dev_priv *uc_priv = NULL;
5854c5d08aSHeiko Schocher struct udevice *dev;
59fe1ef503SSimon Glass ulong offset;
60fe1ef503SSimon Glass int numeric;
6196495d90SSimon Glass int ret;
6296495d90SSimon Glass
63fe1ef503SSimon Glass numeric = isdigit(*name) ? simple_strtoul(name, NULL, 10) : -1;
6496495d90SSimon Glass for (ret = uclass_first_device(UCLASS_GPIO, &dev);
6596495d90SSimon Glass dev;
6696495d90SSimon Glass ret = uclass_next_device(&dev)) {
6796495d90SSimon Glass int len;
6896495d90SSimon Glass
69e564f054SSimon Glass uc_priv = dev_get_uclass_priv(dev);
70fe1ef503SSimon Glass if (numeric != -1) {
71fe1ef503SSimon Glass offset = numeric - uc_priv->gpio_base;
72fe1ef503SSimon Glass /* Allow GPIOs to be numbered from 0 */
7375897910STom Rini if (offset < uc_priv->gpio_count)
74fe1ef503SSimon Glass break;
75fe1ef503SSimon Glass }
76fe1ef503SSimon Glass
7796495d90SSimon Glass len = uc_priv->bank_name ? strlen(uc_priv->bank_name) : 0;
7896495d90SSimon Glass
79939cda5bSSimon Glass if (!strncasecmp(name, uc_priv->bank_name, len)) {
80fe1ef503SSimon Glass if (!strict_strtoul(name + len, 10, &offset))
81fe1ef503SSimon Glass break;
82fe1ef503SSimon Glass }
83fe1ef503SSimon Glass }
84fe1ef503SSimon Glass
85fe1ef503SSimon Glass if (!dev)
86fe1ef503SSimon Glass return ret ? ret : -EINVAL;
87fe1ef503SSimon Glass
8832ec1598SSimon Glass desc->dev = dev;
8932ec1598SSimon Glass desc->offset = offset;
9032ec1598SSimon Glass
9132ec1598SSimon Glass return 0;
9232ec1598SSimon Glass }
9332ec1598SSimon Glass
gpio_lookup_name(const char * name,struct udevice ** devp,unsigned int * offsetp,unsigned int * gpiop)9432ec1598SSimon Glass int gpio_lookup_name(const char *name, struct udevice **devp,
9532ec1598SSimon Glass unsigned int *offsetp, unsigned int *gpiop)
9632ec1598SSimon Glass {
9732ec1598SSimon Glass struct gpio_desc desc;
9832ec1598SSimon Glass int ret;
9932ec1598SSimon Glass
10096495d90SSimon Glass if (devp)
10132ec1598SSimon Glass *devp = NULL;
10232ec1598SSimon Glass ret = dm_gpio_lookup_name(name, &desc);
10332ec1598SSimon Glass if (ret)
10432ec1598SSimon Glass return ret;
10532ec1598SSimon Glass
10632ec1598SSimon Glass if (devp)
10732ec1598SSimon Glass *devp = desc.dev;
10896495d90SSimon Glass if (offsetp)
10932ec1598SSimon Glass *offsetp = desc.offset;
11032ec1598SSimon Glass if (gpiop) {
11132ec1598SSimon Glass struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(desc.dev);
11232ec1598SSimon Glass
11332ec1598SSimon Glass *gpiop = uc_priv->gpio_base + desc.offset;
11432ec1598SSimon Glass }
11596495d90SSimon Glass
116fe1ef503SSimon Glass return 0;
11796495d90SSimon Glass }
11896495d90SSimon Glass
gpio_xlate_offs_flags(struct udevice * dev,struct gpio_desc * desc,struct ofnode_phandle_args * args)1193a57123eSSimon Glass int gpio_xlate_offs_flags(struct udevice *dev, struct gpio_desc *desc,
1203a57123eSSimon Glass struct ofnode_phandle_args *args)
1216c880b77SEric Nelson {
1226c880b77SEric Nelson if (args->args_count < 1)
1236c880b77SEric Nelson return -EINVAL;
1246c880b77SEric Nelson
1256c880b77SEric Nelson desc->offset = args->args[0];
1266c880b77SEric Nelson
1276c880b77SEric Nelson if (args->args_count < 2)
1286c880b77SEric Nelson return 0;
1296c880b77SEric Nelson
1306c880b77SEric Nelson if (args->args[1] & GPIO_ACTIVE_LOW)
1316c880b77SEric Nelson desc->flags = GPIOD_ACTIVE_LOW;
1326c880b77SEric Nelson
1336c880b77SEric Nelson return 0;
1346c880b77SEric Nelson }
1356c880b77SEric Nelson
gpio_find_and_xlate(struct gpio_desc * desc,struct ofnode_phandle_args * args)1363669e0e7SSimon Glass static int gpio_find_and_xlate(struct gpio_desc *desc,
1373a57123eSSimon Glass struct ofnode_phandle_args *args)
1380dac4d51SSimon Glass {
1390dac4d51SSimon Glass struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
1400dac4d51SSimon Glass
1416c880b77SEric Nelson if (ops->xlate)
1426c880b77SEric Nelson return ops->xlate(desc->dev, desc, args);
1430dac4d51SSimon Glass else
1446c880b77SEric Nelson return gpio_xlate_offs_flags(desc->dev, desc, args);
1450dac4d51SSimon Glass }
1460dac4d51SSimon Glass
147*f7de9e82SEddie James #if CONFIG_IS_ENABLED(GPIO_HOG)
14804c095b2SHeiko Schocher
14904c095b2SHeiko Schocher struct gpio_hog_priv {
15004c095b2SHeiko Schocher struct gpio_desc gpiod;
15104c095b2SHeiko Schocher };
15204c095b2SHeiko Schocher
15304c095b2SHeiko Schocher struct gpio_hog_data {
15404c095b2SHeiko Schocher int gpiod_flags;
15504c095b2SHeiko Schocher int value;
15604c095b2SHeiko Schocher u32 val[2];
15704c095b2SHeiko Schocher };
15804c095b2SHeiko Schocher
gpio_hog_ofdata_to_platdata(struct udevice * dev)15904c095b2SHeiko Schocher static int gpio_hog_ofdata_to_platdata(struct udevice *dev)
16004c095b2SHeiko Schocher {
16104c095b2SHeiko Schocher struct gpio_hog_data *plat = dev_get_platdata(dev);
16204c095b2SHeiko Schocher const char *nodename;
16304c095b2SHeiko Schocher int ret;
16404c095b2SHeiko Schocher
16504c095b2SHeiko Schocher plat->value = 0;
16604c095b2SHeiko Schocher if (dev_read_bool(dev, "input")) {
16704c095b2SHeiko Schocher plat->gpiod_flags = GPIOD_IS_IN;
16804c095b2SHeiko Schocher } else if (dev_read_bool(dev, "output-high")) {
16904c095b2SHeiko Schocher plat->value = 1;
17004c095b2SHeiko Schocher plat->gpiod_flags = GPIOD_IS_OUT;
17104c095b2SHeiko Schocher } else if (dev_read_bool(dev, "output-low")) {
17204c095b2SHeiko Schocher plat->gpiod_flags = GPIOD_IS_OUT;
17304c095b2SHeiko Schocher } else {
17404c095b2SHeiko Schocher printf("%s: missing gpio-hog state.\n", __func__);
17504c095b2SHeiko Schocher return -EINVAL;
17604c095b2SHeiko Schocher }
17704c095b2SHeiko Schocher ret = dev_read_u32_array(dev, "gpios", plat->val, 2);
17804c095b2SHeiko Schocher if (ret) {
17904c095b2SHeiko Schocher printf("%s: wrong gpios property, 2 values needed %d\n",
18004c095b2SHeiko Schocher __func__, ret);
18104c095b2SHeiko Schocher return ret;
18204c095b2SHeiko Schocher }
18304c095b2SHeiko Schocher nodename = dev_read_string(dev, "line-name");
184dab778a2SHeiko Schocher if (nodename)
18504c095b2SHeiko Schocher device_set_name(dev, nodename);
18604c095b2SHeiko Schocher
18704c095b2SHeiko Schocher return 0;
18804c095b2SHeiko Schocher }
18904c095b2SHeiko Schocher
gpio_hog_probe(struct udevice * dev)19004c095b2SHeiko Schocher static int gpio_hog_probe(struct udevice *dev)
19104c095b2SHeiko Schocher {
19204c095b2SHeiko Schocher struct gpio_hog_data *plat = dev_get_platdata(dev);
19304c095b2SHeiko Schocher struct gpio_hog_priv *priv = dev_get_priv(dev);
19404c095b2SHeiko Schocher int ret;
19504c095b2SHeiko Schocher
19604c095b2SHeiko Schocher ret = gpio_dev_request_index(dev->parent, dev->name, "gpio-hog",
19704c095b2SHeiko Schocher plat->val[0], plat->gpiod_flags,
19804c095b2SHeiko Schocher plat->val[1], &priv->gpiod);
19904c095b2SHeiko Schocher if (ret < 0) {
20004c095b2SHeiko Schocher debug("%s: node %s could not get gpio.\n", __func__,
20104c095b2SHeiko Schocher dev->name);
20204c095b2SHeiko Schocher return ret;
20304c095b2SHeiko Schocher }
204dab778a2SHeiko Schocher
205dab778a2SHeiko Schocher if (plat->gpiod_flags == GPIOD_IS_OUT) {
206dab778a2SHeiko Schocher ret = dm_gpio_set_value(&priv->gpiod, plat->value);
207dab778a2SHeiko Schocher if (ret < 0) {
208dab778a2SHeiko Schocher debug("%s: node %s could not set gpio.\n", __func__,
209dab778a2SHeiko Schocher dev->name);
210dab778a2SHeiko Schocher return ret;
211dab778a2SHeiko Schocher }
212dab778a2SHeiko Schocher }
21304c095b2SHeiko Schocher
21404c095b2SHeiko Schocher return 0;
21504c095b2SHeiko Schocher }
21604c095b2SHeiko Schocher
gpio_hog_probe_all(void)21704c095b2SHeiko Schocher int gpio_hog_probe_all(void)
21804c095b2SHeiko Schocher {
21904c095b2SHeiko Schocher struct udevice *dev;
22004c095b2SHeiko Schocher int ret;
221dab778a2SHeiko Schocher int retval = 0;
22204c095b2SHeiko Schocher
22304c095b2SHeiko Schocher for (uclass_first_device(UCLASS_NOP, &dev);
22404c095b2SHeiko Schocher dev;
22504c095b2SHeiko Schocher uclass_find_next_device(&dev)) {
22604c095b2SHeiko Schocher if (dev->driver == DM_GET_DRIVER(gpio_hog)) {
22704c095b2SHeiko Schocher ret = device_probe(dev);
228dab778a2SHeiko Schocher if (ret) {
229dab778a2SHeiko Schocher printf("Failed to probe device %s err: %d\n",
230dab778a2SHeiko Schocher dev->name, ret);
231dab778a2SHeiko Schocher retval = ret;
232dab778a2SHeiko Schocher }
23304c095b2SHeiko Schocher }
23404c095b2SHeiko Schocher }
23504c095b2SHeiko Schocher
236dab778a2SHeiko Schocher return retval;
23704c095b2SHeiko Schocher }
23804c095b2SHeiko Schocher
gpio_hog_lookup_name(const char * name,struct gpio_desc ** desc)239dab778a2SHeiko Schocher int gpio_hog_lookup_name(const char *name, struct gpio_desc **desc)
24004c095b2SHeiko Schocher {
24104c095b2SHeiko Schocher struct udevice *dev;
24204c095b2SHeiko Schocher
243dab778a2SHeiko Schocher *desc = NULL;
24404c095b2SHeiko Schocher gpio_hog_probe_all();
24504c095b2SHeiko Schocher if (!uclass_get_device_by_name(UCLASS_NOP, name, &dev)) {
24604c095b2SHeiko Schocher struct gpio_hog_priv *priv = dev_get_priv(dev);
24704c095b2SHeiko Schocher
248dab778a2SHeiko Schocher *desc = &priv->gpiod;
249dab778a2SHeiko Schocher return 0;
25004c095b2SHeiko Schocher }
25104c095b2SHeiko Schocher
252dab778a2SHeiko Schocher return -ENODEV;
25304c095b2SHeiko Schocher }
25404c095b2SHeiko Schocher
25504c095b2SHeiko Schocher U_BOOT_DRIVER(gpio_hog) = {
25604c095b2SHeiko Schocher .name = "gpio_hog",
25704c095b2SHeiko Schocher .id = UCLASS_NOP,
25804c095b2SHeiko Schocher .ofdata_to_platdata = gpio_hog_ofdata_to_platdata,
25904c095b2SHeiko Schocher .probe = gpio_hog_probe,
26004c095b2SHeiko Schocher .priv_auto_alloc_size = sizeof(struct gpio_hog_priv),
26104c095b2SHeiko Schocher .platdata_auto_alloc_size = sizeof(struct gpio_hog_data),
26204c095b2SHeiko Schocher };
26304c095b2SHeiko Schocher #else
gpio_hog_lookup_name(const char * name,struct gpio_desc ** desc)264dab778a2SHeiko Schocher int gpio_hog_lookup_name(const char *name, struct gpio_desc **desc)
26504c095b2SHeiko Schocher {
266dab778a2SHeiko Schocher return 0;
26704c095b2SHeiko Schocher }
26804c095b2SHeiko Schocher #endif
26904c095b2SHeiko Schocher
dm_gpio_request(struct gpio_desc * desc,const char * label)270efa677fbSSimon Glass int dm_gpio_request(struct gpio_desc *desc, const char *label)
271ae7123f8SSimon Glass {
272ae7123f8SSimon Glass struct udevice *dev = desc->dev;
273ae7123f8SSimon Glass struct gpio_dev_priv *uc_priv;
274ae7123f8SSimon Glass char *str;
275ae7123f8SSimon Glass int ret;
276ae7123f8SSimon Glass
277e564f054SSimon Glass uc_priv = dev_get_uclass_priv(dev);
278ae7123f8SSimon Glass if (uc_priv->name[desc->offset])
279ae7123f8SSimon Glass return -EBUSY;
280ae7123f8SSimon Glass str = strdup(label);
281ae7123f8SSimon Glass if (!str)
282ae7123f8SSimon Glass return -ENOMEM;
283ae7123f8SSimon Glass if (gpio_get_ops(dev)->request) {
284ae7123f8SSimon Glass ret = gpio_get_ops(dev)->request(dev, desc->offset, label);
285ae7123f8SSimon Glass if (ret) {
286ae7123f8SSimon Glass free(str);
287ae7123f8SSimon Glass return ret;
288ae7123f8SSimon Glass }
289ae7123f8SSimon Glass }
290ae7123f8SSimon Glass uc_priv->name[desc->offset] = str;
291ae7123f8SSimon Glass
292ae7123f8SSimon Glass return 0;
293ae7123f8SSimon Glass }
294ae7123f8SSimon Glass
dm_gpio_requestf(struct gpio_desc * desc,const char * fmt,...)2953669e0e7SSimon Glass static int dm_gpio_requestf(struct gpio_desc *desc, const char *fmt, ...)
2963669e0e7SSimon Glass {
2974dc5259aSSimon Glass #if !defined(CONFIG_SPL_BUILD) || !defined(CONFIG_USE_TINY_PRINTF)
2983669e0e7SSimon Glass va_list args;
2993669e0e7SSimon Glass char buf[40];
3003669e0e7SSimon Glass
3013669e0e7SSimon Glass va_start(args, fmt);
3023669e0e7SSimon Glass vscnprintf(buf, sizeof(buf), fmt, args);
3033669e0e7SSimon Glass va_end(args);
3043669e0e7SSimon Glass return dm_gpio_request(desc, buf);
3054dc5259aSSimon Glass #else
3064dc5259aSSimon Glass return dm_gpio_request(desc, fmt);
3074dc5259aSSimon Glass #endif
3083669e0e7SSimon Glass }
3093669e0e7SSimon Glass
31096495d90SSimon Glass /**
31196495d90SSimon Glass * gpio_request() - [COMPAT] Request GPIO
31296495d90SSimon Glass * gpio: GPIO number
31396495d90SSimon Glass * label: Name for the requested GPIO
31496495d90SSimon Glass *
315b892d127SSimon Glass * The label is copied and allocated so the caller does not need to keep
316b892d127SSimon Glass * the pointer around.
317b892d127SSimon Glass *
31896495d90SSimon Glass * This function implements the API that's compatible with current
31996495d90SSimon Glass * GPIO API used in U-Boot. The request is forwarded to particular
32096495d90SSimon Glass * GPIO driver. Returns 0 on success, negative value on error.
32196495d90SSimon Glass */
gpio_request(unsigned gpio,const char * label)32296495d90SSimon Glass int gpio_request(unsigned gpio, const char *label)
32396495d90SSimon Glass {
324ae7123f8SSimon Glass struct gpio_desc desc;
32596495d90SSimon Glass int ret;
32696495d90SSimon Glass
327ae7123f8SSimon Glass ret = gpio_to_device(gpio, &desc);
32896495d90SSimon Glass if (ret)
32996495d90SSimon Glass return ret;
33096495d90SSimon Glass
331ae7123f8SSimon Glass return dm_gpio_request(&desc, label);
33296495d90SSimon Glass }
33396495d90SSimon Glass
33496495d90SSimon Glass /**
335d44f597bSSimon Glass * gpio_requestf() - [COMPAT] Request GPIO
336d44f597bSSimon Glass * @gpio: GPIO number
337d44f597bSSimon Glass * @fmt: Format string for the requested GPIO
338d44f597bSSimon Glass * @...: Arguments for the printf() format string
339d44f597bSSimon Glass *
340d44f597bSSimon Glass * This function implements the API that's compatible with current
341d44f597bSSimon Glass * GPIO API used in U-Boot. The request is forwarded to particular
342d44f597bSSimon Glass * GPIO driver. Returns 0 on success, negative value on error.
343d44f597bSSimon Glass */
gpio_requestf(unsigned gpio,const char * fmt,...)344d44f597bSSimon Glass int gpio_requestf(unsigned gpio, const char *fmt, ...)
345d44f597bSSimon Glass {
3464dc5259aSSimon Glass #if !defined(CONFIG_SPL_BUILD) || !defined(CONFIG_USE_TINY_PRINTF)
347d44f597bSSimon Glass va_list args;
348d44f597bSSimon Glass char buf[40];
349d44f597bSSimon Glass
350d44f597bSSimon Glass va_start(args, fmt);
351d44f597bSSimon Glass vscnprintf(buf, sizeof(buf), fmt, args);
352d44f597bSSimon Glass va_end(args);
353d44f597bSSimon Glass return gpio_request(gpio, buf);
3544dc5259aSSimon Glass #else
3554dc5259aSSimon Glass return gpio_request(gpio, fmt);
3564dc5259aSSimon Glass #endif
357d44f597bSSimon Glass }
358d44f597bSSimon Glass
_dm_gpio_free(struct udevice * dev,uint offset)359ae7123f8SSimon Glass int _dm_gpio_free(struct udevice *dev, uint offset)
36096495d90SSimon Glass {
361b892d127SSimon Glass struct gpio_dev_priv *uc_priv;
36296495d90SSimon Glass int ret;
36396495d90SSimon Glass
364e564f054SSimon Glass uc_priv = dev_get_uclass_priv(dev);
365b892d127SSimon Glass if (!uc_priv->name[offset])
366b892d127SSimon Glass return -ENXIO;
367b892d127SSimon Glass if (gpio_get_ops(dev)->free) {
368b892d127SSimon Glass ret = gpio_get_ops(dev)->free(dev, offset);
369b892d127SSimon Glass if (ret)
370b892d127SSimon Glass return ret;
371b892d127SSimon Glass }
372b892d127SSimon Glass
373b892d127SSimon Glass free(uc_priv->name[offset]);
374b892d127SSimon Glass uc_priv->name[offset] = NULL;
375b892d127SSimon Glass
37696495d90SSimon Glass return 0;
377b892d127SSimon Glass }
378b892d127SSimon Glass
379ae7123f8SSimon Glass /**
380ae7123f8SSimon Glass * gpio_free() - [COMPAT] Relinquish GPIO
381ae7123f8SSimon Glass * gpio: GPIO number
382ae7123f8SSimon Glass *
383ae7123f8SSimon Glass * This function implements the API that's compatible with current
384ae7123f8SSimon Glass * GPIO API used in U-Boot. The request is forwarded to particular
385ae7123f8SSimon Glass * GPIO driver. Returns 0 on success, negative value on error.
386ae7123f8SSimon Glass */
gpio_free(unsigned gpio)387ae7123f8SSimon Glass int gpio_free(unsigned gpio)
388b892d127SSimon Glass {
389ae7123f8SSimon Glass struct gpio_desc desc;
390ae7123f8SSimon Glass int ret;
391b892d127SSimon Glass
392ae7123f8SSimon Glass ret = gpio_to_device(gpio, &desc);
393ae7123f8SSimon Glass if (ret)
394ae7123f8SSimon Glass return ret;
395ae7123f8SSimon Glass
396ae7123f8SSimon Glass return _dm_gpio_free(desc.dev, desc.offset);
397ae7123f8SSimon Glass }
398ae7123f8SSimon Glass
check_reserved(const struct gpio_desc * desc,const char * func)39917c43f1aSSimon Glass static int check_reserved(const struct gpio_desc *desc, const char *func)
400ae7123f8SSimon Glass {
401eca48665SSimon Glass struct gpio_dev_priv *uc_priv;
402ae7123f8SSimon Glass
403eca48665SSimon Glass if (!dm_gpio_is_valid(desc))
404eca48665SSimon Glass return -ENOENT;
405eca48665SSimon Glass
406eca48665SSimon Glass uc_priv = dev_get_uclass_priv(desc->dev);
407ae7123f8SSimon Glass if (!uc_priv->name[desc->offset]) {
408b892d127SSimon Glass printf("%s: %s: error: gpio %s%d not reserved\n",
409ae7123f8SSimon Glass desc->dev->name, func,
410ae7123f8SSimon Glass uc_priv->bank_name ? uc_priv->bank_name : "",
411ae7123f8SSimon Glass desc->offset);
412b892d127SSimon Glass return -EBUSY;
413b892d127SSimon Glass }
414b892d127SSimon Glass
415b892d127SSimon Glass return 0;
41696495d90SSimon Glass }
41796495d90SSimon Glass
41896495d90SSimon Glass /**
41996495d90SSimon Glass * gpio_direction_input() - [COMPAT] Set GPIO direction to input
42096495d90SSimon Glass * gpio: GPIO number
42196495d90SSimon Glass *
42296495d90SSimon Glass * This function implements the API that's compatible with current
42396495d90SSimon Glass * GPIO API used in U-Boot. The request is forwarded to particular
42496495d90SSimon Glass * GPIO driver. Returns 0 on success, negative value on error.
42596495d90SSimon Glass */
gpio_direction_input(unsigned gpio)42696495d90SSimon Glass int gpio_direction_input(unsigned gpio)
42796495d90SSimon Glass {
428ae7123f8SSimon Glass struct gpio_desc desc;
42996495d90SSimon Glass int ret;
43096495d90SSimon Glass
431ae7123f8SSimon Glass ret = gpio_to_device(gpio, &desc);
43296495d90SSimon Glass if (ret)
43396495d90SSimon Glass return ret;
434ae7123f8SSimon Glass ret = check_reserved(&desc, "dir_input");
435ae7123f8SSimon Glass if (ret)
436ae7123f8SSimon Glass return ret;
43796495d90SSimon Glass
438ae7123f8SSimon Glass return gpio_get_ops(desc.dev)->direction_input(desc.dev, desc.offset);
43996495d90SSimon Glass }
44096495d90SSimon Glass
44196495d90SSimon Glass /**
44296495d90SSimon Glass * gpio_direction_output() - [COMPAT] Set GPIO direction to output and set value
44396495d90SSimon Glass * gpio: GPIO number
44496495d90SSimon Glass * value: Logical value to be set on the GPIO pin
44596495d90SSimon Glass *
44696495d90SSimon Glass * This function implements the API that's compatible with current
44796495d90SSimon Glass * GPIO API used in U-Boot. The request is forwarded to particular
44896495d90SSimon Glass * GPIO driver. Returns 0 on success, negative value on error.
44996495d90SSimon Glass */
gpio_direction_output(unsigned gpio,int value)45096495d90SSimon Glass int gpio_direction_output(unsigned gpio, int value)
45196495d90SSimon Glass {
452ae7123f8SSimon Glass struct gpio_desc desc;
45396495d90SSimon Glass int ret;
45496495d90SSimon Glass
455ae7123f8SSimon Glass ret = gpio_to_device(gpio, &desc);
45696495d90SSimon Glass if (ret)
45796495d90SSimon Glass return ret;
458ae7123f8SSimon Glass ret = check_reserved(&desc, "dir_output");
459ae7123f8SSimon Glass if (ret)
460ae7123f8SSimon Glass return ret;
46196495d90SSimon Glass
462ae7123f8SSimon Glass return gpio_get_ops(desc.dev)->direction_output(desc.dev,
463ae7123f8SSimon Glass desc.offset, value);
464ae7123f8SSimon Glass }
465ae7123f8SSimon Glass
dm_gpio_get_value(const struct gpio_desc * desc)46617c43f1aSSimon Glass int dm_gpio_get_value(const struct gpio_desc *desc)
467ae7123f8SSimon Glass {
468ae7123f8SSimon Glass int value;
469ae7123f8SSimon Glass int ret;
470ae7123f8SSimon Glass
471ae7123f8SSimon Glass ret = check_reserved(desc, "get_value");
472ae7123f8SSimon Glass if (ret)
473ae7123f8SSimon Glass return ret;
474ae7123f8SSimon Glass
475ae7123f8SSimon Glass value = gpio_get_ops(desc->dev)->get_value(desc->dev, desc->offset);
476ae7123f8SSimon Glass
477ae7123f8SSimon Glass return desc->flags & GPIOD_ACTIVE_LOW ? !value : value;
478ae7123f8SSimon Glass }
479ae7123f8SSimon Glass
dm_gpio_set_value(const struct gpio_desc * desc,int value)48017c43f1aSSimon Glass int dm_gpio_set_value(const struct gpio_desc *desc, int value)
481ae7123f8SSimon Glass {
482ae7123f8SSimon Glass int ret;
483ae7123f8SSimon Glass
484ae7123f8SSimon Glass ret = check_reserved(desc, "set_value");
485ae7123f8SSimon Glass if (ret)
486ae7123f8SSimon Glass return ret;
487ae7123f8SSimon Glass
488ae7123f8SSimon Glass if (desc->flags & GPIOD_ACTIVE_LOW)
489ae7123f8SSimon Glass value = !value;
490ae7123f8SSimon Glass gpio_get_ops(desc->dev)->set_value(desc->dev, desc->offset, value);
491ae7123f8SSimon Glass return 0;
492ae7123f8SSimon Glass }
493ae7123f8SSimon Glass
dm_gpio_get_open_drain(struct gpio_desc * desc)49453ecdfb9Smario.six@gdsys.cc int dm_gpio_get_open_drain(struct gpio_desc *desc)
49553ecdfb9Smario.six@gdsys.cc {
49653ecdfb9Smario.six@gdsys.cc struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
49753ecdfb9Smario.six@gdsys.cc int ret;
49853ecdfb9Smario.six@gdsys.cc
49953ecdfb9Smario.six@gdsys.cc ret = check_reserved(desc, "get_open_drain");
50053ecdfb9Smario.six@gdsys.cc if (ret)
50153ecdfb9Smario.six@gdsys.cc return ret;
50253ecdfb9Smario.six@gdsys.cc
50353ecdfb9Smario.six@gdsys.cc if (ops->set_open_drain)
50453ecdfb9Smario.six@gdsys.cc return ops->get_open_drain(desc->dev, desc->offset);
50553ecdfb9Smario.six@gdsys.cc else
50653ecdfb9Smario.six@gdsys.cc return -ENOSYS;
50753ecdfb9Smario.six@gdsys.cc }
50853ecdfb9Smario.six@gdsys.cc
dm_gpio_set_open_drain(struct gpio_desc * desc,int value)50953ecdfb9Smario.six@gdsys.cc int dm_gpio_set_open_drain(struct gpio_desc *desc, int value)
51053ecdfb9Smario.six@gdsys.cc {
51153ecdfb9Smario.six@gdsys.cc struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
51253ecdfb9Smario.six@gdsys.cc int ret;
51353ecdfb9Smario.six@gdsys.cc
51453ecdfb9Smario.six@gdsys.cc ret = check_reserved(desc, "set_open_drain");
51553ecdfb9Smario.six@gdsys.cc if (ret)
51653ecdfb9Smario.six@gdsys.cc return ret;
51753ecdfb9Smario.six@gdsys.cc
51853ecdfb9Smario.six@gdsys.cc if (ops->set_open_drain)
51953ecdfb9Smario.six@gdsys.cc ret = ops->set_open_drain(desc->dev, desc->offset, value);
52053ecdfb9Smario.six@gdsys.cc else
52153ecdfb9Smario.six@gdsys.cc return 0; /* feature not supported -> ignore setting */
52253ecdfb9Smario.six@gdsys.cc
52353ecdfb9Smario.six@gdsys.cc return ret;
52453ecdfb9Smario.six@gdsys.cc }
52553ecdfb9Smario.six@gdsys.cc
dm_gpio_set_dir_flags(struct gpio_desc * desc,ulong flags)526ae7123f8SSimon Glass int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
527ae7123f8SSimon Glass {
528ae7123f8SSimon Glass struct udevice *dev = desc->dev;
529ae7123f8SSimon Glass struct dm_gpio_ops *ops = gpio_get_ops(dev);
530ae7123f8SSimon Glass int ret;
531ae7123f8SSimon Glass
532ae7123f8SSimon Glass ret = check_reserved(desc, "set_dir");
533ae7123f8SSimon Glass if (ret)
534ae7123f8SSimon Glass return ret;
535ae7123f8SSimon Glass
536ae7123f8SSimon Glass if (flags & GPIOD_IS_OUT) {
537ae7123f8SSimon Glass int value = flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0;
538ae7123f8SSimon Glass
539ae7123f8SSimon Glass if (flags & GPIOD_ACTIVE_LOW)
540ae7123f8SSimon Glass value = !value;
541ae7123f8SSimon Glass ret = ops->direction_output(dev, desc->offset, value);
542ae7123f8SSimon Glass } else if (flags & GPIOD_IS_IN) {
543ae7123f8SSimon Glass ret = ops->direction_input(dev, desc->offset);
544ae7123f8SSimon Glass }
545ae7123f8SSimon Glass if (ret)
546ae7123f8SSimon Glass return ret;
547ae7123f8SSimon Glass /*
548ae7123f8SSimon Glass * Update desc->flags here, so that GPIO_ACTIVE_LOW is honoured in
549ae7123f8SSimon Glass * futures
550ae7123f8SSimon Glass */
551ae7123f8SSimon Glass desc->flags = flags;
552ae7123f8SSimon Glass
553ae7123f8SSimon Glass return 0;
554ae7123f8SSimon Glass }
555ae7123f8SSimon Glass
dm_gpio_set_dir(struct gpio_desc * desc)556ae7123f8SSimon Glass int dm_gpio_set_dir(struct gpio_desc *desc)
557ae7123f8SSimon Glass {
558ae7123f8SSimon Glass return dm_gpio_set_dir_flags(desc, desc->flags);
55996495d90SSimon Glass }
56096495d90SSimon Glass
56196495d90SSimon Glass /**
56296495d90SSimon Glass * gpio_get_value() - [COMPAT] Sample GPIO pin and return it's value
56396495d90SSimon Glass * gpio: GPIO number
56496495d90SSimon Glass *
56596495d90SSimon Glass * This function implements the API that's compatible with current
56696495d90SSimon Glass * GPIO API used in U-Boot. The request is forwarded to particular
56796495d90SSimon Glass * GPIO driver. Returns the value of the GPIO pin, or negative value
56896495d90SSimon Glass * on error.
56996495d90SSimon Glass */
gpio_get_value(unsigned gpio)57096495d90SSimon Glass int gpio_get_value(unsigned gpio)
57196495d90SSimon Glass {
57296495d90SSimon Glass int ret;
57396495d90SSimon Glass
574ae7123f8SSimon Glass struct gpio_desc desc;
575ae7123f8SSimon Glass
576ae7123f8SSimon Glass ret = gpio_to_device(gpio, &desc);
57796495d90SSimon Glass if (ret)
57896495d90SSimon Glass return ret;
579ae7123f8SSimon Glass return dm_gpio_get_value(&desc);
58096495d90SSimon Glass }
58196495d90SSimon Glass
58296495d90SSimon Glass /**
58396495d90SSimon Glass * gpio_set_value() - [COMPAT] Configure logical value on GPIO pin
58496495d90SSimon Glass * gpio: GPIO number
58596495d90SSimon Glass * value: Logical value to be set on the GPIO pin.
58696495d90SSimon Glass *
58796495d90SSimon Glass * This function implements the API that's compatible with current
58896495d90SSimon Glass * GPIO API used in U-Boot. The request is forwarded to particular
58996495d90SSimon Glass * GPIO driver. Returns 0 on success, negative value on error.
59096495d90SSimon Glass */
gpio_set_value(unsigned gpio,int value)59196495d90SSimon Glass int gpio_set_value(unsigned gpio, int value)
59296495d90SSimon Glass {
593ae7123f8SSimon Glass struct gpio_desc desc;
59496495d90SSimon Glass int ret;
59596495d90SSimon Glass
596ae7123f8SSimon Glass ret = gpio_to_device(gpio, &desc);
59796495d90SSimon Glass if (ret)
59896495d90SSimon Glass return ret;
599ae7123f8SSimon Glass return dm_gpio_set_value(&desc, value);
60096495d90SSimon Glass }
60196495d90SSimon Glass
gpio_get_bank_info(struct udevice * dev,int * bit_count)60254c5d08aSHeiko Schocher const char *gpio_get_bank_info(struct udevice *dev, int *bit_count)
60396495d90SSimon Glass {
60496495d90SSimon Glass struct gpio_dev_priv *priv;
60596495d90SSimon Glass
60696495d90SSimon Glass /* Must be called on an active device */
607e564f054SSimon Glass priv = dev_get_uclass_priv(dev);
60896495d90SSimon Glass assert(priv);
60996495d90SSimon Glass
61096495d90SSimon Glass *bit_count = priv->gpio_count;
61196495d90SSimon Glass return priv->bank_name;
61296495d90SSimon Glass }
61396495d90SSimon Glass
6146449a506SSimon Glass static const char * const gpio_function[GPIOF_COUNT] = {
6156449a506SSimon Glass "input",
6166449a506SSimon Glass "output",
6176449a506SSimon Glass "unused",
6186449a506SSimon Glass "unknown",
6196449a506SSimon Glass "func",
6206449a506SSimon Glass };
6216449a506SSimon Glass
get_function(struct udevice * dev,int offset,bool skip_unused,const char ** namep)622fb07f97dSMasahiro Yamada static int get_function(struct udevice *dev, int offset, bool skip_unused,
6236449a506SSimon Glass const char **namep)
6246449a506SSimon Glass {
625e564f054SSimon Glass struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
6266449a506SSimon Glass struct dm_gpio_ops *ops = gpio_get_ops(dev);
6276449a506SSimon Glass
6286449a506SSimon Glass BUILD_BUG_ON(GPIOF_COUNT != ARRAY_SIZE(gpio_function));
6296449a506SSimon Glass if (!device_active(dev))
6306449a506SSimon Glass return -ENODEV;
6316449a506SSimon Glass if (offset < 0 || offset >= uc_priv->gpio_count)
6326449a506SSimon Glass return -EINVAL;
6336449a506SSimon Glass if (namep)
6346449a506SSimon Glass *namep = uc_priv->name[offset];
6356449a506SSimon Glass if (skip_unused && !uc_priv->name[offset])
6366449a506SSimon Glass return GPIOF_UNUSED;
6376449a506SSimon Glass if (ops->get_function) {
6386449a506SSimon Glass int ret;
6396449a506SSimon Glass
6406449a506SSimon Glass ret = ops->get_function(dev, offset);
6416449a506SSimon Glass if (ret < 0)
6426449a506SSimon Glass return ret;
6436449a506SSimon Glass if (ret >= ARRAY_SIZE(gpio_function))
6446449a506SSimon Glass return -ENODATA;
6456449a506SSimon Glass return ret;
6466449a506SSimon Glass }
6476449a506SSimon Glass
6486449a506SSimon Glass return GPIOF_UNKNOWN;
6496449a506SSimon Glass }
6506449a506SSimon Glass
gpio_get_function(struct udevice * dev,int offset,const char ** namep)6516449a506SSimon Glass int gpio_get_function(struct udevice *dev, int offset, const char **namep)
6526449a506SSimon Glass {
6536449a506SSimon Glass return get_function(dev, offset, true, namep);
6546449a506SSimon Glass }
6556449a506SSimon Glass
gpio_get_raw_function(struct udevice * dev,int offset,const char ** namep)6566449a506SSimon Glass int gpio_get_raw_function(struct udevice *dev, int offset, const char **namep)
6576449a506SSimon Glass {
6586449a506SSimon Glass return get_function(dev, offset, false, namep);
6596449a506SSimon Glass }
6606449a506SSimon Glass
gpio_get_status(struct udevice * dev,int offset,char * buf,int buffsize)6610757535aSSimon Glass int gpio_get_status(struct udevice *dev, int offset, char *buf, int buffsize)
6620757535aSSimon Glass {
6630757535aSSimon Glass struct dm_gpio_ops *ops = gpio_get_ops(dev);
6640757535aSSimon Glass struct gpio_dev_priv *priv;
6650757535aSSimon Glass char *str = buf;
6660757535aSSimon Glass int func;
6670757535aSSimon Glass int ret;
6680757535aSSimon Glass int len;
6690757535aSSimon Glass
6700757535aSSimon Glass BUILD_BUG_ON(GPIOF_COUNT != ARRAY_SIZE(gpio_function));
6710757535aSSimon Glass
6720757535aSSimon Glass *buf = 0;
673e564f054SSimon Glass priv = dev_get_uclass_priv(dev);
6740757535aSSimon Glass ret = gpio_get_raw_function(dev, offset, NULL);
6750757535aSSimon Glass if (ret < 0)
6760757535aSSimon Glass return ret;
6770757535aSSimon Glass func = ret;
6780757535aSSimon Glass len = snprintf(str, buffsize, "%s%d: %s",
6790757535aSSimon Glass priv->bank_name ? priv->bank_name : "",
6800757535aSSimon Glass offset, gpio_function[func]);
6810757535aSSimon Glass if (func == GPIOF_INPUT || func == GPIOF_OUTPUT ||
6820757535aSSimon Glass func == GPIOF_UNUSED) {
6830757535aSSimon Glass const char *label;
6840757535aSSimon Glass bool used;
6850757535aSSimon Glass
6860757535aSSimon Glass ret = ops->get_value(dev, offset);
6870757535aSSimon Glass if (ret < 0)
6880757535aSSimon Glass return ret;
6890757535aSSimon Glass used = gpio_get_function(dev, offset, &label) != GPIOF_UNUSED;
6900757535aSSimon Glass snprintf(str + len, buffsize - len, ": %d [%c]%s%s",
6910757535aSSimon Glass ret,
6920757535aSSimon Glass used ? 'x' : ' ',
6930757535aSSimon Glass used ? " " : "",
6940757535aSSimon Glass label ? label : "");
6950757535aSSimon Glass }
6960757535aSSimon Glass
6970757535aSSimon Glass return 0;
6980757535aSSimon Glass }
6990757535aSSimon Glass
gpio_claim_vector(const int * gpio_num_array,const char * fmt)700962f5cafSSimon Glass int gpio_claim_vector(const int *gpio_num_array, const char *fmt)
701962f5cafSSimon Glass {
702962f5cafSSimon Glass int i, ret;
703962f5cafSSimon Glass int gpio;
704962f5cafSSimon Glass
705962f5cafSSimon Glass for (i = 0; i < 32; i++) {
706962f5cafSSimon Glass gpio = gpio_num_array[i];
707962f5cafSSimon Glass if (gpio == -1)
708962f5cafSSimon Glass break;
709962f5cafSSimon Glass ret = gpio_requestf(gpio, fmt, i);
710962f5cafSSimon Glass if (ret)
711962f5cafSSimon Glass goto err;
712962f5cafSSimon Glass ret = gpio_direction_input(gpio);
713962f5cafSSimon Glass if (ret) {
714962f5cafSSimon Glass gpio_free(gpio);
715962f5cafSSimon Glass goto err;
716962f5cafSSimon Glass }
717962f5cafSSimon Glass }
718962f5cafSSimon Glass
719962f5cafSSimon Glass return 0;
720962f5cafSSimon Glass err:
721962f5cafSSimon Glass for (i--; i >= 0; i--)
722962f5cafSSimon Glass gpio_free(gpio_num_array[i]);
723962f5cafSSimon Glass
724962f5cafSSimon Glass return ret;
725962f5cafSSimon Glass }
726962f5cafSSimon Glass
727e5901c94SSimon Glass /*
728e5901c94SSimon Glass * get a number comprised of multiple GPIO values. gpio_num_array points to
729e5901c94SSimon Glass * the array of gpio pin numbers to scan, terminated by -1.
730e5901c94SSimon Glass */
gpio_get_values_as_int(const int * gpio_list)731962f5cafSSimon Glass int gpio_get_values_as_int(const int *gpio_list)
732e5901c94SSimon Glass {
733e5901c94SSimon Glass int gpio;
734e5901c94SSimon Glass unsigned bitmask = 1;
735e5901c94SSimon Glass unsigned vector = 0;
736962f5cafSSimon Glass int ret;
737e5901c94SSimon Glass
738e5901c94SSimon Glass while (bitmask &&
739962f5cafSSimon Glass ((gpio = *gpio_list++) != -1)) {
740962f5cafSSimon Glass ret = gpio_get_value(gpio);
741962f5cafSSimon Glass if (ret < 0)
742962f5cafSSimon Glass return ret;
743962f5cafSSimon Glass else if (ret)
744e5901c94SSimon Glass vector |= bitmask;
745e5901c94SSimon Glass bitmask <<= 1;
746e5901c94SSimon Glass }
747962f5cafSSimon Glass
748e5901c94SSimon Glass return vector;
749e5901c94SSimon Glass }
750e5901c94SSimon Glass
dm_gpio_get_values_as_int(const struct gpio_desc * desc_list,int count)75117c43f1aSSimon Glass int dm_gpio_get_values_as_int(const struct gpio_desc *desc_list, int count)
752bbf24780SSimon Glass {
753bbf24780SSimon Glass unsigned bitmask = 1;
754bbf24780SSimon Glass unsigned vector = 0;
755bbf24780SSimon Glass int ret, i;
756bbf24780SSimon Glass
757bbf24780SSimon Glass for (i = 0; i < count; i++) {
758bbf24780SSimon Glass ret = dm_gpio_get_value(&desc_list[i]);
759bbf24780SSimon Glass if (ret < 0)
760bbf24780SSimon Glass return ret;
761bbf24780SSimon Glass else if (ret)
762bbf24780SSimon Glass vector |= bitmask;
763bbf24780SSimon Glass bitmask <<= 1;
764bbf24780SSimon Glass }
765bbf24780SSimon Glass
766bbf24780SSimon Glass return vector;
767bbf24780SSimon Glass }
768bbf24780SSimon Glass
769dab778a2SHeiko Schocher /**
770dab778a2SHeiko Schocher * gpio_request_tail: common work for requesting a gpio.
771dab778a2SHeiko Schocher *
772dab778a2SHeiko Schocher * ret: return value from previous work in function which calls
773dab778a2SHeiko Schocher * this function.
774dab778a2SHeiko Schocher * This seems bogus (why calling this function instead not
775dab778a2SHeiko Schocher * calling it and end caller function instead?).
776dab778a2SHeiko Schocher * Because on error in caller function we want to set some
777dab778a2SHeiko Schocher * default values in gpio desc and have a common error
778dab778a2SHeiko Schocher * debug message, which provides this function.
779dab778a2SHeiko Schocher * nodename: Name of node for which gpio gets requested
780dab778a2SHeiko Schocher * used for gpio label name.
781dab778a2SHeiko Schocher * args: pointer to output arguments structure
782dab778a2SHeiko Schocher * list_name: Name of GPIO list
783dab778a2SHeiko Schocher * used for gpio label name.
784dab778a2SHeiko Schocher * index: gpio index in gpio list
785dab778a2SHeiko Schocher * used for gpio label name.
786dab778a2SHeiko Schocher * desc: pointer to gpio descriptor, filled from this
787dab778a2SHeiko Schocher * function.
788dab778a2SHeiko Schocher * flags: gpio flags to use.
789dab778a2SHeiko Schocher * add_index: should index added to gpio label name
790dab778a2SHeiko Schocher * gpio_dev: pointer to gpio device from which the gpio
791dab778a2SHeiko Schocher * will be requested. If NULL try to get the
792dab778a2SHeiko Schocher * gpio device with uclass_get_device_by_ofnode()
793dab778a2SHeiko Schocher *
794dab778a2SHeiko Schocher * return: In error case this function sets default values in
795dab778a2SHeiko Schocher * gpio descriptor, also emmits a debug message.
796dab778a2SHeiko Schocher * On success it returns 0 else the error code from
797dab778a2SHeiko Schocher * function calls, or the error code passed through
798dab778a2SHeiko Schocher * ret to this function.
799dab778a2SHeiko Schocher *
800dab778a2SHeiko Schocher */
gpio_request_tail(int ret,const char * nodename,struct ofnode_phandle_args * args,const char * list_name,int index,struct gpio_desc * desc,int flags,bool add_index,struct udevice * gpio_dev)80104c095b2SHeiko Schocher static int gpio_request_tail(int ret, const char *nodename,
8023a57123eSSimon Glass struct ofnode_phandle_args *args,
8033669e0e7SSimon Glass const char *list_name, int index,
80404c095b2SHeiko Schocher struct gpio_desc *desc, int flags,
805dab778a2SHeiko Schocher bool add_index, struct udevice *gpio_dev)
8063669e0e7SSimon Glass {
807dab778a2SHeiko Schocher desc->dev = gpio_dev;
8083669e0e7SSimon Glass desc->offset = 0;
8096c880b77SEric Nelson desc->flags = 0;
8103a57123eSSimon Glass if (ret)
8113669e0e7SSimon Glass goto err;
8123669e0e7SSimon Glass
81304c095b2SHeiko Schocher if (!desc->dev) {
8143a57123eSSimon Glass ret = uclass_get_device_by_ofnode(UCLASS_GPIO, args->node,
8153669e0e7SSimon Glass &desc->dev);
8163669e0e7SSimon Glass if (ret) {
817dab778a2SHeiko Schocher debug("%s: uclass_get_device_by_ofnode failed\n",
818dab778a2SHeiko Schocher __func__);
8193669e0e7SSimon Glass goto err;
8203669e0e7SSimon Glass }
82104c095b2SHeiko Schocher }
8223a57123eSSimon Glass ret = gpio_find_and_xlate(desc, args);
8233669e0e7SSimon Glass if (ret) {
8243669e0e7SSimon Glass debug("%s: gpio_find_and_xlate failed\n", __func__);
8253669e0e7SSimon Glass goto err;
8263669e0e7SSimon Glass }
8273669e0e7SSimon Glass ret = dm_gpio_requestf(desc, add_index ? "%s.%s%d" : "%s.%s",
82804c095b2SHeiko Schocher nodename, list_name, index);
8293669e0e7SSimon Glass if (ret) {
8303669e0e7SSimon Glass debug("%s: dm_gpio_requestf failed\n", __func__);
8313669e0e7SSimon Glass goto err;
8323669e0e7SSimon Glass }
8333669e0e7SSimon Glass ret = dm_gpio_set_dir_flags(desc, flags | desc->flags);
8343669e0e7SSimon Glass if (ret) {
8353669e0e7SSimon Glass debug("%s: dm_gpio_set_dir failed\n", __func__);
8363669e0e7SSimon Glass goto err;
8373669e0e7SSimon Glass }
8383669e0e7SSimon Glass
8393669e0e7SSimon Glass return 0;
8403669e0e7SSimon Glass err:
8413669e0e7SSimon Glass debug("%s: Node '%s', property '%s', failed to request GPIO index %d: %d\n",
84204c095b2SHeiko Schocher __func__, nodename, list_name, index, ret);
8433669e0e7SSimon Glass return ret;
8443669e0e7SSimon Glass }
8453669e0e7SSimon Glass
_gpio_request_by_name_nodev(ofnode node,const char * list_name,int index,struct gpio_desc * desc,int flags,bool add_index)846150c5afeSSimon Glass static int _gpio_request_by_name_nodev(ofnode node, const char *list_name,
847150c5afeSSimon Glass int index, struct gpio_desc *desc,
848150c5afeSSimon Glass int flags, bool add_index)
8493a57123eSSimon Glass {
8503a57123eSSimon Glass struct ofnode_phandle_args args;
8513a57123eSSimon Glass int ret;
8523a57123eSSimon Glass
853150c5afeSSimon Glass ret = ofnode_parse_phandle_with_args(node, list_name, "#gpio-cells", 0,
854150c5afeSSimon Glass index, &args);
8553a57123eSSimon Glass
85604c095b2SHeiko Schocher return gpio_request_tail(ret, ofnode_get_name(node), &args, list_name,
85704c095b2SHeiko Schocher index, desc, flags, add_index, NULL);
8583a57123eSSimon Glass }
8593a57123eSSimon Glass
gpio_request_by_name_nodev(ofnode node,const char * list_name,int index,struct gpio_desc * desc,int flags)860150c5afeSSimon Glass int gpio_request_by_name_nodev(ofnode node, const char *list_name, int index,
8613669e0e7SSimon Glass struct gpio_desc *desc, int flags)
8623669e0e7SSimon Glass {
863150c5afeSSimon Glass return _gpio_request_by_name_nodev(node, list_name, index, desc, flags,
864150c5afeSSimon Glass index > 0);
8653669e0e7SSimon Glass }
8663669e0e7SSimon Glass
gpio_request_by_name(struct udevice * dev,const char * list_name,int index,struct gpio_desc * desc,int flags)8673669e0e7SSimon Glass int gpio_request_by_name(struct udevice *dev, const char *list_name, int index,
8683669e0e7SSimon Glass struct gpio_desc *desc, int flags)
8693669e0e7SSimon Glass {
870150c5afeSSimon Glass struct ofnode_phandle_args args;
87104c095b2SHeiko Schocher ofnode node;
872150c5afeSSimon Glass int ret;
873150c5afeSSimon Glass
874150c5afeSSimon Glass ret = dev_read_phandle_with_args(dev, list_name, "#gpio-cells", 0,
875150c5afeSSimon Glass index, &args);
87604c095b2SHeiko Schocher node = dev_ofnode(dev);
87704c095b2SHeiko Schocher return gpio_request_tail(ret, ofnode_get_name(node), &args, list_name,
87804c095b2SHeiko Schocher index, desc, flags, index > 0, NULL);
8793669e0e7SSimon Glass }
8803669e0e7SSimon Glass
gpio_request_list_by_name_nodev(ofnode node,const char * list_name,struct gpio_desc * desc,int max_count,int flags)881150c5afeSSimon Glass int gpio_request_list_by_name_nodev(ofnode node, const char *list_name,
8823669e0e7SSimon Glass struct gpio_desc *desc, int max_count,
8833669e0e7SSimon Glass int flags)
8843669e0e7SSimon Glass {
8853669e0e7SSimon Glass int count;
8863669e0e7SSimon Glass int ret;
8873669e0e7SSimon Glass
8882984e7a1SPrzemyslaw Marczak for (count = 0; count < max_count; count++) {
889150c5afeSSimon Glass ret = _gpio_request_by_name_nodev(node, list_name, count,
8903669e0e7SSimon Glass &desc[count], flags, true);
8913669e0e7SSimon Glass if (ret == -ENOENT)
8923669e0e7SSimon Glass break;
8933669e0e7SSimon Glass else if (ret)
8943669e0e7SSimon Glass goto err;
8953669e0e7SSimon Glass }
8963669e0e7SSimon Glass
8973669e0e7SSimon Glass /* We ran out of GPIOs in the list */
8983669e0e7SSimon Glass return count;
8993669e0e7SSimon Glass
9003669e0e7SSimon Glass err:
9013669e0e7SSimon Glass gpio_free_list_nodev(desc, count - 1);
9023669e0e7SSimon Glass
9033669e0e7SSimon Glass return ret;
9043669e0e7SSimon Glass }
9053669e0e7SSimon Glass
gpio_request_list_by_name(struct udevice * dev,const char * list_name,struct gpio_desc * desc,int max_count,int flags)9063669e0e7SSimon Glass int gpio_request_list_by_name(struct udevice *dev, const char *list_name,
9073669e0e7SSimon Glass struct gpio_desc *desc, int max_count,
9083669e0e7SSimon Glass int flags)
9093669e0e7SSimon Glass {
9103669e0e7SSimon Glass /*
9113669e0e7SSimon Glass * This isn't ideal since we don't use dev->name in the debug()
9123669e0e7SSimon Glass * calls in gpio_request_by_name(), but we can do this until
9133669e0e7SSimon Glass * gpio_request_list_by_name_nodev() can be dropped.
9143669e0e7SSimon Glass */
915150c5afeSSimon Glass return gpio_request_list_by_name_nodev(dev_ofnode(dev), list_name, desc,
916150c5afeSSimon Glass max_count, flags);
9173669e0e7SSimon Glass }
9183669e0e7SSimon Glass
gpio_get_list_count(struct udevice * dev,const char * list_name)9193669e0e7SSimon Glass int gpio_get_list_count(struct udevice *dev, const char *list_name)
9203669e0e7SSimon Glass {
9213669e0e7SSimon Glass int ret;
9223669e0e7SSimon Glass
923e160f7d4SSimon Glass ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev),
9243669e0e7SSimon Glass list_name, "#gpio-cells", 0, -1,
9253669e0e7SSimon Glass NULL);
9263669e0e7SSimon Glass if (ret) {
9273669e0e7SSimon Glass debug("%s: Node '%s', property '%s', GPIO count failed: %d\n",
9283669e0e7SSimon Glass __func__, dev->name, list_name, ret);
9293669e0e7SSimon Glass }
9303669e0e7SSimon Glass
9313669e0e7SSimon Glass return ret;
9323669e0e7SSimon Glass }
9333669e0e7SSimon Glass
dm_gpio_free(struct udevice * dev,struct gpio_desc * desc)9343669e0e7SSimon Glass int dm_gpio_free(struct udevice *dev, struct gpio_desc *desc)
9353669e0e7SSimon Glass {
9363669e0e7SSimon Glass /* For now, we don't do any checking of dev */
9373669e0e7SSimon Glass return _dm_gpio_free(desc->dev, desc->offset);
9383669e0e7SSimon Glass }
9393669e0e7SSimon Glass
gpio_free_list(struct udevice * dev,struct gpio_desc * desc,int count)9403669e0e7SSimon Glass int gpio_free_list(struct udevice *dev, struct gpio_desc *desc, int count)
9413669e0e7SSimon Glass {
9423669e0e7SSimon Glass int i;
9433669e0e7SSimon Glass
9443669e0e7SSimon Glass /* For now, we don't do any checking of dev */
9453669e0e7SSimon Glass for (i = 0; i < count; i++)
9463669e0e7SSimon Glass dm_gpio_free(dev, &desc[i]);
9473669e0e7SSimon Glass
9483669e0e7SSimon Glass return 0;
9493669e0e7SSimon Glass }
9503669e0e7SSimon Glass
gpio_free_list_nodev(struct gpio_desc * desc,int count)9513669e0e7SSimon Glass int gpio_free_list_nodev(struct gpio_desc *desc, int count)
9523669e0e7SSimon Glass {
9533669e0e7SSimon Glass return gpio_free_list(NULL, desc, count);
9543669e0e7SSimon Glass }
9553669e0e7SSimon Glass
95696495d90SSimon Glass /* We need to renumber the GPIOs when any driver is probed/removed */
gpio_renumber(struct udevice * removed_dev)957b892d127SSimon Glass static int gpio_renumber(struct udevice *removed_dev)
95896495d90SSimon Glass {
95996495d90SSimon Glass struct gpio_dev_priv *uc_priv;
96054c5d08aSHeiko Schocher struct udevice *dev;
96196495d90SSimon Glass struct uclass *uc;
96296495d90SSimon Glass unsigned base;
96396495d90SSimon Glass int ret;
96496495d90SSimon Glass
96596495d90SSimon Glass ret = uclass_get(UCLASS_GPIO, &uc);
96696495d90SSimon Glass if (ret)
96796495d90SSimon Glass return ret;
96896495d90SSimon Glass
96996495d90SSimon Glass /* Ensure that we have a base for each bank */
97096495d90SSimon Glass base = 0;
97196495d90SSimon Glass uclass_foreach_dev(dev, uc) {
972b892d127SSimon Glass if (device_active(dev) && dev != removed_dev) {
973e564f054SSimon Glass uc_priv = dev_get_uclass_priv(dev);
97496495d90SSimon Glass uc_priv->gpio_base = base;
97596495d90SSimon Glass base += uc_priv->gpio_count;
97696495d90SSimon Glass }
97796495d90SSimon Glass }
97896495d90SSimon Glass
97996495d90SSimon Glass return 0;
98096495d90SSimon Glass }
98196495d90SSimon Glass
gpio_get_number(const struct gpio_desc * desc)98217c43f1aSSimon Glass int gpio_get_number(const struct gpio_desc *desc)
98356a71f89SSimon Glass {
98456a71f89SSimon Glass struct udevice *dev = desc->dev;
98556a71f89SSimon Glass struct gpio_dev_priv *uc_priv;
98656a71f89SSimon Glass
98756a71f89SSimon Glass if (!dev)
98856a71f89SSimon Glass return -1;
98956a71f89SSimon Glass uc_priv = dev->uclass_priv;
99056a71f89SSimon Glass
99156a71f89SSimon Glass return uc_priv->gpio_base + desc->offset;
99256a71f89SSimon Glass }
99356a71f89SSimon Glass
gpio_post_probe(struct udevice * dev)99454c5d08aSHeiko Schocher static int gpio_post_probe(struct udevice *dev)
99596495d90SSimon Glass {
996e564f054SSimon Glass struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
997b892d127SSimon Glass
998b892d127SSimon Glass uc_priv->name = calloc(uc_priv->gpio_count, sizeof(char *));
999b892d127SSimon Glass if (!uc_priv->name)
1000b892d127SSimon Glass return -ENOMEM;
1001b892d127SSimon Glass
1002b892d127SSimon Glass return gpio_renumber(NULL);
100396495d90SSimon Glass }
100496495d90SSimon Glass
gpio_pre_remove(struct udevice * dev)100554c5d08aSHeiko Schocher static int gpio_pre_remove(struct udevice *dev)
100696495d90SSimon Glass {
1007e564f054SSimon Glass struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
1008b892d127SSimon Glass int i;
1009b892d127SSimon Glass
1010b892d127SSimon Glass for (i = 0; i < uc_priv->gpio_count; i++) {
1011b892d127SSimon Glass if (uc_priv->name[i])
1012b892d127SSimon Glass free(uc_priv->name[i]);
1013b892d127SSimon Glass }
1014b892d127SSimon Glass free(uc_priv->name);
1015b892d127SSimon Glass
1016b892d127SSimon Glass return gpio_renumber(dev);
101796495d90SSimon Glass }
101896495d90SSimon Glass
gpio_dev_request_index(struct udevice * dev,const char * nodename,char * list_name,int index,int flags,int dtflags,struct gpio_desc * desc)101904c095b2SHeiko Schocher int gpio_dev_request_index(struct udevice *dev, const char *nodename,
102004c095b2SHeiko Schocher char *list_name, int index, int flags,
102104c095b2SHeiko Schocher int dtflags, struct gpio_desc *desc)
102204c095b2SHeiko Schocher {
102304c095b2SHeiko Schocher struct ofnode_phandle_args args;
102404c095b2SHeiko Schocher
102504c095b2SHeiko Schocher args.node = ofnode_null();
102604c095b2SHeiko Schocher args.args_count = 2;
102704c095b2SHeiko Schocher args.args[0] = index;
102804c095b2SHeiko Schocher args.args[1] = dtflags;
102904c095b2SHeiko Schocher
103004c095b2SHeiko Schocher return gpio_request_tail(0, nodename, &args, list_name, index, desc,
103104c095b2SHeiko Schocher flags, 0, dev);
103204c095b2SHeiko Schocher }
103304c095b2SHeiko Schocher
gpio_post_bind(struct udevice * dev)10341b4c2aa2SMichal Simek static int gpio_post_bind(struct udevice *dev)
10351b4c2aa2SMichal Simek {
10361b4c2aa2SMichal Simek #if defined(CONFIG_NEEDS_MANUAL_RELOC)
10371b4c2aa2SMichal Simek struct dm_gpio_ops *ops = (struct dm_gpio_ops *)device_get_ops(dev);
10381b4c2aa2SMichal Simek static int reloc_done;
10391b4c2aa2SMichal Simek
10401b4c2aa2SMichal Simek if (!reloc_done) {
10411b4c2aa2SMichal Simek if (ops->request)
10421b4c2aa2SMichal Simek ops->request += gd->reloc_off;
10431b4c2aa2SMichal Simek if (ops->free)
10441b4c2aa2SMichal Simek ops->free += gd->reloc_off;
10451b4c2aa2SMichal Simek if (ops->direction_input)
10461b4c2aa2SMichal Simek ops->direction_input += gd->reloc_off;
10471b4c2aa2SMichal Simek if (ops->direction_output)
10481b4c2aa2SMichal Simek ops->direction_output += gd->reloc_off;
10491b4c2aa2SMichal Simek if (ops->get_value)
10501b4c2aa2SMichal Simek ops->get_value += gd->reloc_off;
10511b4c2aa2SMichal Simek if (ops->set_value)
10521b4c2aa2SMichal Simek ops->set_value += gd->reloc_off;
10531b4c2aa2SMichal Simek if (ops->get_open_drain)
10541b4c2aa2SMichal Simek ops->get_open_drain += gd->reloc_off;
10551b4c2aa2SMichal Simek if (ops->set_open_drain)
10561b4c2aa2SMichal Simek ops->set_open_drain += gd->reloc_off;
10571b4c2aa2SMichal Simek if (ops->get_function)
10581b4c2aa2SMichal Simek ops->get_function += gd->reloc_off;
10591b4c2aa2SMichal Simek if (ops->xlate)
10601b4c2aa2SMichal Simek ops->xlate += gd->reloc_off;
10611b4c2aa2SMichal Simek
10621b4c2aa2SMichal Simek reloc_done++;
10631b4c2aa2SMichal Simek }
10641b4c2aa2SMichal Simek #endif
106504c095b2SHeiko Schocher
1066*f7de9e82SEddie James if (CONFIG_IS_ENABLED(GPIO_HOG)) {
1067*f7de9e82SEddie James struct udevice *child;
1068*f7de9e82SEddie James ofnode node;
1069*f7de9e82SEddie James
107004c095b2SHeiko Schocher dev_for_each_subnode(node, dev) {
107104c095b2SHeiko Schocher if (ofnode_read_bool(node, "gpio-hog")) {
107204c095b2SHeiko Schocher const char *name = ofnode_get_name(node);
1073dab778a2SHeiko Schocher int ret;
107404c095b2SHeiko Schocher
1075dab778a2SHeiko Schocher ret = device_bind_driver_to_node(dev,
1076dab778a2SHeiko Schocher "gpio_hog",
1077dab778a2SHeiko Schocher name, node,
1078dab778a2SHeiko Schocher &child);
1079dab778a2SHeiko Schocher if (ret)
1080dab778a2SHeiko Schocher return ret;
108104c095b2SHeiko Schocher }
108204c095b2SHeiko Schocher }
1083dab778a2SHeiko Schocher }
10841b4c2aa2SMichal Simek return 0;
10851b4c2aa2SMichal Simek }
10861b4c2aa2SMichal Simek
108796495d90SSimon Glass UCLASS_DRIVER(gpio) = {
108896495d90SSimon Glass .id = UCLASS_GPIO,
108996495d90SSimon Glass .name = "gpio",
1090ae89bb0dSBhuvanchandra DV .flags = DM_UC_FLAG_SEQ_ALIAS,
109196495d90SSimon Glass .post_probe = gpio_post_probe,
10921b4c2aa2SMichal Simek .post_bind = gpio_post_bind,
109396495d90SSimon Glass .pre_remove = gpio_pre_remove,
109496495d90SSimon Glass .per_device_auto_alloc_size = sizeof(struct gpio_dev_priv),
109596495d90SSimon Glass };
1096