1*96495d90SSimon Glass /* 2*96495d90SSimon Glass * Copyright (c) 2013 Google, Inc 3*96495d90SSimon Glass * 4*96495d90SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 5*96495d90SSimon Glass */ 6*96495d90SSimon Glass 7*96495d90SSimon Glass #include <common.h> 8*96495d90SSimon Glass #include <dm.h> 9*96495d90SSimon Glass #include <errno.h> 10*96495d90SSimon Glass #include <asm/gpio.h> 11*96495d90SSimon Glass 12*96495d90SSimon Glass /** 13*96495d90SSimon Glass * gpio_to_device() - Convert global GPIO number to device, number 14*96495d90SSimon Glass * gpio: The numeric representation of the GPIO 15*96495d90SSimon Glass * 16*96495d90SSimon Glass * Convert the GPIO number to an entry in the list of GPIOs 17*96495d90SSimon Glass * or GPIO blocks registered with the GPIO controller. Returns 18*96495d90SSimon Glass * entry on success, NULL on error. 19*96495d90SSimon Glass */ 20*96495d90SSimon Glass static int gpio_to_device(unsigned int gpio, struct device **devp, 21*96495d90SSimon Glass unsigned int *offset) 22*96495d90SSimon Glass { 23*96495d90SSimon Glass struct gpio_dev_priv *uc_priv; 24*96495d90SSimon Glass struct device *dev; 25*96495d90SSimon Glass int ret; 26*96495d90SSimon Glass 27*96495d90SSimon Glass for (ret = uclass_first_device(UCLASS_GPIO, &dev); 28*96495d90SSimon Glass dev; 29*96495d90SSimon Glass ret = uclass_next_device(&dev)) { 30*96495d90SSimon Glass uc_priv = dev->uclass_priv; 31*96495d90SSimon Glass if (gpio >= uc_priv->gpio_base && 32*96495d90SSimon Glass gpio < uc_priv->gpio_base + uc_priv->gpio_count) { 33*96495d90SSimon Glass *devp = dev; 34*96495d90SSimon Glass *offset = gpio - uc_priv->gpio_base; 35*96495d90SSimon Glass return 0; 36*96495d90SSimon Glass } 37*96495d90SSimon Glass } 38*96495d90SSimon Glass 39*96495d90SSimon Glass /* No such GPIO */ 40*96495d90SSimon Glass return ret ? ret : -EINVAL; 41*96495d90SSimon Glass } 42*96495d90SSimon Glass 43*96495d90SSimon Glass int gpio_lookup_name(const char *name, struct device **devp, 44*96495d90SSimon Glass unsigned int *offsetp, unsigned int *gpiop) 45*96495d90SSimon Glass { 46*96495d90SSimon Glass struct gpio_dev_priv *uc_priv; 47*96495d90SSimon Glass struct device *dev; 48*96495d90SSimon Glass int ret; 49*96495d90SSimon Glass 50*96495d90SSimon Glass if (devp) 51*96495d90SSimon Glass *devp = NULL; 52*96495d90SSimon Glass for (ret = uclass_first_device(UCLASS_GPIO, &dev); 53*96495d90SSimon Glass dev; 54*96495d90SSimon Glass ret = uclass_next_device(&dev)) { 55*96495d90SSimon Glass ulong offset; 56*96495d90SSimon Glass int len; 57*96495d90SSimon Glass 58*96495d90SSimon Glass uc_priv = dev->uclass_priv; 59*96495d90SSimon Glass len = uc_priv->bank_name ? strlen(uc_priv->bank_name) : 0; 60*96495d90SSimon Glass 61*96495d90SSimon Glass if (!strncmp(name, uc_priv->bank_name, len)) { 62*96495d90SSimon Glass if (strict_strtoul(name + len, 10, &offset)) 63*96495d90SSimon Glass continue; 64*96495d90SSimon Glass if (devp) 65*96495d90SSimon Glass *devp = dev; 66*96495d90SSimon Glass if (offsetp) 67*96495d90SSimon Glass *offsetp = offset; 68*96495d90SSimon Glass if (gpiop) 69*96495d90SSimon Glass *gpiop = uc_priv->gpio_base + offset; 70*96495d90SSimon Glass return 0; 71*96495d90SSimon Glass } 72*96495d90SSimon Glass } 73*96495d90SSimon Glass 74*96495d90SSimon Glass return ret ? ret : -EINVAL; 75*96495d90SSimon Glass } 76*96495d90SSimon Glass 77*96495d90SSimon Glass /** 78*96495d90SSimon Glass * gpio_request() - [COMPAT] Request GPIO 79*96495d90SSimon Glass * gpio: GPIO number 80*96495d90SSimon Glass * label: Name for the requested GPIO 81*96495d90SSimon Glass * 82*96495d90SSimon Glass * This function implements the API that's compatible with current 83*96495d90SSimon Glass * GPIO API used in U-Boot. The request is forwarded to particular 84*96495d90SSimon Glass * GPIO driver. Returns 0 on success, negative value on error. 85*96495d90SSimon Glass */ 86*96495d90SSimon Glass int gpio_request(unsigned gpio, const char *label) 87*96495d90SSimon Glass { 88*96495d90SSimon Glass unsigned int offset; 89*96495d90SSimon Glass struct device *dev; 90*96495d90SSimon Glass int ret; 91*96495d90SSimon Glass 92*96495d90SSimon Glass ret = gpio_to_device(gpio, &dev, &offset); 93*96495d90SSimon Glass if (ret) 94*96495d90SSimon Glass return ret; 95*96495d90SSimon Glass 96*96495d90SSimon Glass if (!gpio_get_ops(dev)->request) 97*96495d90SSimon Glass return 0; 98*96495d90SSimon Glass 99*96495d90SSimon Glass return gpio_get_ops(dev)->request(dev, offset, label); 100*96495d90SSimon Glass } 101*96495d90SSimon Glass 102*96495d90SSimon Glass /** 103*96495d90SSimon Glass * gpio_free() - [COMPAT] Relinquish GPIO 104*96495d90SSimon Glass * gpio: GPIO number 105*96495d90SSimon Glass * 106*96495d90SSimon Glass * This function implements the API that's compatible with current 107*96495d90SSimon Glass * GPIO API used in U-Boot. The request is forwarded to particular 108*96495d90SSimon Glass * GPIO driver. Returns 0 on success, negative value on error. 109*96495d90SSimon Glass */ 110*96495d90SSimon Glass int gpio_free(unsigned gpio) 111*96495d90SSimon Glass { 112*96495d90SSimon Glass unsigned int offset; 113*96495d90SSimon Glass struct device *dev; 114*96495d90SSimon Glass int ret; 115*96495d90SSimon Glass 116*96495d90SSimon Glass ret = gpio_to_device(gpio, &dev, &offset); 117*96495d90SSimon Glass if (ret) 118*96495d90SSimon Glass return ret; 119*96495d90SSimon Glass 120*96495d90SSimon Glass if (!gpio_get_ops(dev)->free) 121*96495d90SSimon Glass return 0; 122*96495d90SSimon Glass return gpio_get_ops(dev)->free(dev, offset); 123*96495d90SSimon Glass } 124*96495d90SSimon Glass 125*96495d90SSimon Glass /** 126*96495d90SSimon Glass * gpio_direction_input() - [COMPAT] Set GPIO direction to input 127*96495d90SSimon Glass * gpio: GPIO number 128*96495d90SSimon Glass * 129*96495d90SSimon Glass * This function implements the API that's compatible with current 130*96495d90SSimon Glass * GPIO API used in U-Boot. The request is forwarded to particular 131*96495d90SSimon Glass * GPIO driver. Returns 0 on success, negative value on error. 132*96495d90SSimon Glass */ 133*96495d90SSimon Glass int gpio_direction_input(unsigned gpio) 134*96495d90SSimon Glass { 135*96495d90SSimon Glass unsigned int offset; 136*96495d90SSimon Glass struct device *dev; 137*96495d90SSimon Glass int ret; 138*96495d90SSimon Glass 139*96495d90SSimon Glass ret = gpio_to_device(gpio, &dev, &offset); 140*96495d90SSimon Glass if (ret) 141*96495d90SSimon Glass return ret; 142*96495d90SSimon Glass 143*96495d90SSimon Glass return gpio_get_ops(dev)->direction_input(dev, offset); 144*96495d90SSimon Glass } 145*96495d90SSimon Glass 146*96495d90SSimon Glass /** 147*96495d90SSimon Glass * gpio_direction_output() - [COMPAT] Set GPIO direction to output and set value 148*96495d90SSimon Glass * gpio: GPIO number 149*96495d90SSimon Glass * value: Logical value to be set on the GPIO pin 150*96495d90SSimon Glass * 151*96495d90SSimon Glass * This function implements the API that's compatible with current 152*96495d90SSimon Glass * GPIO API used in U-Boot. The request is forwarded to particular 153*96495d90SSimon Glass * GPIO driver. Returns 0 on success, negative value on error. 154*96495d90SSimon Glass */ 155*96495d90SSimon Glass int gpio_direction_output(unsigned gpio, int value) 156*96495d90SSimon Glass { 157*96495d90SSimon Glass unsigned int offset; 158*96495d90SSimon Glass struct device *dev; 159*96495d90SSimon Glass int ret; 160*96495d90SSimon Glass 161*96495d90SSimon Glass ret = gpio_to_device(gpio, &dev, &offset); 162*96495d90SSimon Glass if (ret) 163*96495d90SSimon Glass return ret; 164*96495d90SSimon Glass 165*96495d90SSimon Glass return gpio_get_ops(dev)->direction_output(dev, offset, value); 166*96495d90SSimon Glass } 167*96495d90SSimon Glass 168*96495d90SSimon Glass /** 169*96495d90SSimon Glass * gpio_get_value() - [COMPAT] Sample GPIO pin and return it's value 170*96495d90SSimon Glass * gpio: GPIO number 171*96495d90SSimon Glass * 172*96495d90SSimon Glass * This function implements the API that's compatible with current 173*96495d90SSimon Glass * GPIO API used in U-Boot. The request is forwarded to particular 174*96495d90SSimon Glass * GPIO driver. Returns the value of the GPIO pin, or negative value 175*96495d90SSimon Glass * on error. 176*96495d90SSimon Glass */ 177*96495d90SSimon Glass int gpio_get_value(unsigned gpio) 178*96495d90SSimon Glass { 179*96495d90SSimon Glass unsigned int offset; 180*96495d90SSimon Glass struct device *dev; 181*96495d90SSimon Glass int ret; 182*96495d90SSimon Glass 183*96495d90SSimon Glass ret = gpio_to_device(gpio, &dev, &offset); 184*96495d90SSimon Glass if (ret) 185*96495d90SSimon Glass return ret; 186*96495d90SSimon Glass 187*96495d90SSimon Glass return gpio_get_ops(dev)->get_value(dev, offset); 188*96495d90SSimon Glass } 189*96495d90SSimon Glass 190*96495d90SSimon Glass /** 191*96495d90SSimon Glass * gpio_set_value() - [COMPAT] Configure logical value on GPIO pin 192*96495d90SSimon Glass * gpio: GPIO number 193*96495d90SSimon Glass * value: Logical value to be set on the GPIO pin. 194*96495d90SSimon Glass * 195*96495d90SSimon Glass * This function implements the API that's compatible with current 196*96495d90SSimon Glass * GPIO API used in U-Boot. The request is forwarded to particular 197*96495d90SSimon Glass * GPIO driver. Returns 0 on success, negative value on error. 198*96495d90SSimon Glass */ 199*96495d90SSimon Glass int gpio_set_value(unsigned gpio, int value) 200*96495d90SSimon Glass { 201*96495d90SSimon Glass unsigned int offset; 202*96495d90SSimon Glass struct device *dev; 203*96495d90SSimon Glass int ret; 204*96495d90SSimon Glass 205*96495d90SSimon Glass ret = gpio_to_device(gpio, &dev, &offset); 206*96495d90SSimon Glass if (ret) 207*96495d90SSimon Glass return ret; 208*96495d90SSimon Glass 209*96495d90SSimon Glass return gpio_get_ops(dev)->set_value(dev, offset, value); 210*96495d90SSimon Glass } 211*96495d90SSimon Glass 212*96495d90SSimon Glass const char *gpio_get_bank_info(struct device *dev, int *bit_count) 213*96495d90SSimon Glass { 214*96495d90SSimon Glass struct gpio_dev_priv *priv; 215*96495d90SSimon Glass 216*96495d90SSimon Glass /* Must be called on an active device */ 217*96495d90SSimon Glass priv = dev->uclass_priv; 218*96495d90SSimon Glass assert(priv); 219*96495d90SSimon Glass 220*96495d90SSimon Glass *bit_count = priv->gpio_count; 221*96495d90SSimon Glass return priv->bank_name; 222*96495d90SSimon Glass } 223*96495d90SSimon Glass 224*96495d90SSimon Glass /* We need to renumber the GPIOs when any driver is probed/removed */ 225*96495d90SSimon Glass static int gpio_renumber(void) 226*96495d90SSimon Glass { 227*96495d90SSimon Glass struct gpio_dev_priv *uc_priv; 228*96495d90SSimon Glass struct device *dev; 229*96495d90SSimon Glass struct uclass *uc; 230*96495d90SSimon Glass unsigned base; 231*96495d90SSimon Glass int ret; 232*96495d90SSimon Glass 233*96495d90SSimon Glass ret = uclass_get(UCLASS_GPIO, &uc); 234*96495d90SSimon Glass if (ret) 235*96495d90SSimon Glass return ret; 236*96495d90SSimon Glass 237*96495d90SSimon Glass /* Ensure that we have a base for each bank */ 238*96495d90SSimon Glass base = 0; 239*96495d90SSimon Glass uclass_foreach_dev(dev, uc) { 240*96495d90SSimon Glass if (device_active(dev)) { 241*96495d90SSimon Glass uc_priv = dev->uclass_priv; 242*96495d90SSimon Glass uc_priv->gpio_base = base; 243*96495d90SSimon Glass base += uc_priv->gpio_count; 244*96495d90SSimon Glass } 245*96495d90SSimon Glass } 246*96495d90SSimon Glass 247*96495d90SSimon Glass return 0; 248*96495d90SSimon Glass } 249*96495d90SSimon Glass 250*96495d90SSimon Glass static int gpio_post_probe(struct device *dev) 251*96495d90SSimon Glass { 252*96495d90SSimon Glass return gpio_renumber(); 253*96495d90SSimon Glass } 254*96495d90SSimon Glass 255*96495d90SSimon Glass static int gpio_pre_remove(struct device *dev) 256*96495d90SSimon Glass { 257*96495d90SSimon Glass return gpio_renumber(); 258*96495d90SSimon Glass } 259*96495d90SSimon Glass 260*96495d90SSimon Glass UCLASS_DRIVER(gpio) = { 261*96495d90SSimon Glass .id = UCLASS_GPIO, 262*96495d90SSimon Glass .name = "gpio", 263*96495d90SSimon Glass .post_probe = gpio_post_probe, 264*96495d90SSimon Glass .pre_remove = gpio_pre_remove, 265*96495d90SSimon Glass .per_device_auto_alloc_size = sizeof(struct gpio_dev_priv), 266*96495d90SSimon Glass }; 267