1308252adSMarek Vasut /* 2308252adSMarek Vasut * Copyright (c) 2009 Wind River Systems, Inc. 3308252adSMarek Vasut * Tom Rix <Tom.Rix@windriver.com> 4308252adSMarek Vasut * 5bcd4d4ebSWolfgang Denk * SPDX-License-Identifier: GPL-2.0 6308252adSMarek Vasut * 7308252adSMarek Vasut * This work is derived from the linux 2.6.27 kernel source 8308252adSMarek Vasut * To fetch, use the kernel repository 9308252adSMarek Vasut * git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git 10308252adSMarek Vasut * Use the v2.6.27 tag. 11308252adSMarek Vasut * 12308252adSMarek Vasut * Below is the original's header including its copyright 13308252adSMarek Vasut * 14308252adSMarek Vasut * linux/arch/arm/plat-omap/gpio.c 15308252adSMarek Vasut * 16308252adSMarek Vasut * Support functions for OMAP GPIO 17308252adSMarek Vasut * 18308252adSMarek Vasut * Copyright (C) 2003-2005 Nokia Corporation 19308252adSMarek Vasut * Written by Juha Yrjölä <juha.yrjola@nokia.com> 20308252adSMarek Vasut */ 21308252adSMarek Vasut #include <common.h> 225915a2adSSimon Glass #include <dm.h> 23*0a9e3405STom Rini #include <fdtdec.h> 24308252adSMarek Vasut #include <asm/gpio.h> 25308252adSMarek Vasut #include <asm/io.h> 26308252adSMarek Vasut #include <asm/errno.h> 27*0a9e3405STom Rini #include <malloc.h> 28*0a9e3405STom Rini 29*0a9e3405STom Rini DECLARE_GLOBAL_DATA_PTR; 30308252adSMarek Vasut 31308252adSMarek Vasut #define OMAP_GPIO_DIR_OUT 0 32308252adSMarek Vasut #define OMAP_GPIO_DIR_IN 1 33308252adSMarek Vasut 345915a2adSSimon Glass #ifdef CONFIG_DM_GPIO 355915a2adSSimon Glass 365915a2adSSimon Glass #define GPIO_PER_BANK 32 375915a2adSSimon Glass 385915a2adSSimon Glass struct gpio_bank { 395915a2adSSimon Glass /* TODO(sjg@chromium.org): Can we use a struct here? */ 405915a2adSSimon Glass void *base; /* address of registers in physical memory */ 415915a2adSSimon Glass }; 425915a2adSSimon Glass 435915a2adSSimon Glass #endif 445915a2adSSimon Glass 45308252adSMarek Vasut static inline int get_gpio_index(int gpio) 46308252adSMarek Vasut { 47308252adSMarek Vasut return gpio & 0x1f; 48308252adSMarek Vasut } 49308252adSMarek Vasut 50dcee1ab3SNikita Kiryanov int gpio_is_valid(int gpio) 51308252adSMarek Vasut { 5287bd05d7SAxel Lin return (gpio >= 0) && (gpio < OMAP_MAX_GPIO); 53308252adSMarek Vasut } 54308252adSMarek Vasut 55308252adSMarek Vasut static void _set_gpio_direction(const struct gpio_bank *bank, int gpio, 56308252adSMarek Vasut int is_input) 57308252adSMarek Vasut { 58308252adSMarek Vasut void *reg = bank->base; 59308252adSMarek Vasut u32 l; 60308252adSMarek Vasut 61308252adSMarek Vasut reg += OMAP_GPIO_OE; 62*0a9e3405STom Rini 63308252adSMarek Vasut l = __raw_readl(reg); 64308252adSMarek Vasut if (is_input) 65308252adSMarek Vasut l |= 1 << gpio; 66308252adSMarek Vasut else 67308252adSMarek Vasut l &= ~(1 << gpio); 68308252adSMarek Vasut __raw_writel(l, reg); 69308252adSMarek Vasut } 70308252adSMarek Vasut 71308252adSMarek Vasut /** 72308252adSMarek Vasut * Get the direction of the GPIO by reading the GPIO_OE register 73308252adSMarek Vasut * corresponding to the specified bank. 74308252adSMarek Vasut */ 75308252adSMarek Vasut static int _get_gpio_direction(const struct gpio_bank *bank, int gpio) 76308252adSMarek Vasut { 77308252adSMarek Vasut void *reg = bank->base; 78308252adSMarek Vasut u32 v; 79308252adSMarek Vasut 80308252adSMarek Vasut reg += OMAP_GPIO_OE; 81308252adSMarek Vasut 82308252adSMarek Vasut v = __raw_readl(reg); 83308252adSMarek Vasut 84308252adSMarek Vasut if (v & (1 << gpio)) 85308252adSMarek Vasut return OMAP_GPIO_DIR_IN; 86308252adSMarek Vasut else 87308252adSMarek Vasut return OMAP_GPIO_DIR_OUT; 88308252adSMarek Vasut } 89308252adSMarek Vasut 90308252adSMarek Vasut static void _set_gpio_dataout(const struct gpio_bank *bank, int gpio, 91308252adSMarek Vasut int enable) 92308252adSMarek Vasut { 93308252adSMarek Vasut void *reg = bank->base; 94308252adSMarek Vasut u32 l = 0; 95308252adSMarek Vasut 96308252adSMarek Vasut if (enable) 97308252adSMarek Vasut reg += OMAP_GPIO_SETDATAOUT; 98308252adSMarek Vasut else 99308252adSMarek Vasut reg += OMAP_GPIO_CLEARDATAOUT; 100*0a9e3405STom Rini 101308252adSMarek Vasut l = 1 << gpio; 102308252adSMarek Vasut __raw_writel(l, reg); 103308252adSMarek Vasut } 104308252adSMarek Vasut 105d57b6114SSimon Glass static int _get_gpio_value(const struct gpio_bank *bank, int gpio) 106d57b6114SSimon Glass { 107d57b6114SSimon Glass void *reg = bank->base; 108d57b6114SSimon Glass int input; 109d57b6114SSimon Glass 110d57b6114SSimon Glass input = _get_gpio_direction(bank, gpio); 111d57b6114SSimon Glass switch (input) { 112d57b6114SSimon Glass case OMAP_GPIO_DIR_IN: 113d57b6114SSimon Glass reg += OMAP_GPIO_DATAIN; 114d57b6114SSimon Glass break; 115d57b6114SSimon Glass case OMAP_GPIO_DIR_OUT: 116d57b6114SSimon Glass reg += OMAP_GPIO_DATAOUT; 117d57b6114SSimon Glass break; 118d57b6114SSimon Glass default: 119d57b6114SSimon Glass return -1; 120d57b6114SSimon Glass } 121d57b6114SSimon Glass 122d57b6114SSimon Glass return (__raw_readl(reg) & (1 << gpio)) != 0; 123d57b6114SSimon Glass } 124d57b6114SSimon Glass 1255915a2adSSimon Glass #ifndef CONFIG_DM_GPIO 1265915a2adSSimon Glass 127d57b6114SSimon Glass static inline const struct gpio_bank *get_gpio_bank(int gpio) 128d57b6114SSimon Glass { 129d57b6114SSimon Glass return &omap_gpio_bank[gpio >> 5]; 130d57b6114SSimon Glass } 131d57b6114SSimon Glass 132d57b6114SSimon Glass static int check_gpio(int gpio) 133d57b6114SSimon Glass { 134d57b6114SSimon Glass if (!gpio_is_valid(gpio)) { 135d57b6114SSimon Glass printf("ERROR : check_gpio: invalid GPIO %d\n", gpio); 136d57b6114SSimon Glass return -1; 137d57b6114SSimon Glass } 138d57b6114SSimon Glass return 0; 139d57b6114SSimon Glass } 140d57b6114SSimon Glass 141308252adSMarek Vasut /** 142308252adSMarek Vasut * Set value of the specified gpio 143308252adSMarek Vasut */ 144308252adSMarek Vasut int gpio_set_value(unsigned gpio, int value) 145308252adSMarek Vasut { 146308252adSMarek Vasut const struct gpio_bank *bank; 147308252adSMarek Vasut 148308252adSMarek Vasut if (check_gpio(gpio) < 0) 149308252adSMarek Vasut return -1; 150308252adSMarek Vasut bank = get_gpio_bank(gpio); 151308252adSMarek Vasut _set_gpio_dataout(bank, get_gpio_index(gpio), value); 152308252adSMarek Vasut 153308252adSMarek Vasut return 0; 154308252adSMarek Vasut } 155308252adSMarek Vasut 156308252adSMarek Vasut /** 157308252adSMarek Vasut * Get value of the specified gpio 158308252adSMarek Vasut */ 159308252adSMarek Vasut int gpio_get_value(unsigned gpio) 160308252adSMarek Vasut { 161308252adSMarek Vasut const struct gpio_bank *bank; 162308252adSMarek Vasut 163308252adSMarek Vasut if (check_gpio(gpio) < 0) 164308252adSMarek Vasut return -1; 165308252adSMarek Vasut bank = get_gpio_bank(gpio); 166d57b6114SSimon Glass 167d57b6114SSimon Glass return _get_gpio_value(bank, get_gpio_index(gpio)); 168308252adSMarek Vasut } 169308252adSMarek Vasut 170308252adSMarek Vasut /** 171308252adSMarek Vasut * Set gpio direction as input 172308252adSMarek Vasut */ 173308252adSMarek Vasut int gpio_direction_input(unsigned gpio) 174308252adSMarek Vasut { 175308252adSMarek Vasut const struct gpio_bank *bank; 176308252adSMarek Vasut 177308252adSMarek Vasut if (check_gpio(gpio) < 0) 178308252adSMarek Vasut return -1; 179308252adSMarek Vasut 180308252adSMarek Vasut bank = get_gpio_bank(gpio); 181308252adSMarek Vasut _set_gpio_direction(bank, get_gpio_index(gpio), 1); 182308252adSMarek Vasut 183308252adSMarek Vasut return 0; 184308252adSMarek Vasut } 185308252adSMarek Vasut 186308252adSMarek Vasut /** 187308252adSMarek Vasut * Set gpio direction as output 188308252adSMarek Vasut */ 189308252adSMarek Vasut int gpio_direction_output(unsigned gpio, int value) 190308252adSMarek Vasut { 191308252adSMarek Vasut const struct gpio_bank *bank; 192308252adSMarek Vasut 193308252adSMarek Vasut if (check_gpio(gpio) < 0) 194308252adSMarek Vasut return -1; 195308252adSMarek Vasut 196308252adSMarek Vasut bank = get_gpio_bank(gpio); 197308252adSMarek Vasut _set_gpio_dataout(bank, get_gpio_index(gpio), value); 198308252adSMarek Vasut _set_gpio_direction(bank, get_gpio_index(gpio), 0); 199308252adSMarek Vasut 200308252adSMarek Vasut return 0; 201308252adSMarek Vasut } 202308252adSMarek Vasut 203308252adSMarek Vasut /** 204308252adSMarek Vasut * Request a gpio before using it. 205308252adSMarek Vasut * 206308252adSMarek Vasut * NOTE: Argument 'label' is unused. 207308252adSMarek Vasut */ 208308252adSMarek Vasut int gpio_request(unsigned gpio, const char *label) 209308252adSMarek Vasut { 210308252adSMarek Vasut if (check_gpio(gpio) < 0) 211308252adSMarek Vasut return -1; 212308252adSMarek Vasut 213308252adSMarek Vasut return 0; 214308252adSMarek Vasut } 215308252adSMarek Vasut 216308252adSMarek Vasut /** 217308252adSMarek Vasut * Reset and free the gpio after using it. 218308252adSMarek Vasut */ 219308252adSMarek Vasut int gpio_free(unsigned gpio) 220308252adSMarek Vasut { 221308252adSMarek Vasut return 0; 222308252adSMarek Vasut } 2235915a2adSSimon Glass 2245915a2adSSimon Glass #else /* new driver model interface CONFIG_DM_GPIO */ 2255915a2adSSimon Glass 2265915a2adSSimon Glass /* set GPIO pin 'gpio' as an input */ 2275915a2adSSimon Glass static int omap_gpio_direction_input(struct udevice *dev, unsigned offset) 2285915a2adSSimon Glass { 2295915a2adSSimon Glass struct gpio_bank *bank = dev_get_priv(dev); 2305915a2adSSimon Glass 2315915a2adSSimon Glass /* Configure GPIO direction as input. */ 2325915a2adSSimon Glass _set_gpio_direction(bank, offset, 1); 2335915a2adSSimon Glass 2345915a2adSSimon Glass return 0; 2355915a2adSSimon Glass } 2365915a2adSSimon Glass 2375915a2adSSimon Glass /* set GPIO pin 'gpio' as an output, with polarity 'value' */ 2385915a2adSSimon Glass static int omap_gpio_direction_output(struct udevice *dev, unsigned offset, 2395915a2adSSimon Glass int value) 2405915a2adSSimon Glass { 2415915a2adSSimon Glass struct gpio_bank *bank = dev_get_priv(dev); 2425915a2adSSimon Glass 2435915a2adSSimon Glass _set_gpio_dataout(bank, offset, value); 2445915a2adSSimon Glass _set_gpio_direction(bank, offset, 0); 2455915a2adSSimon Glass 2465915a2adSSimon Glass return 0; 2475915a2adSSimon Glass } 2485915a2adSSimon Glass 2495915a2adSSimon Glass /* read GPIO IN value of pin 'gpio' */ 2505915a2adSSimon Glass static int omap_gpio_get_value(struct udevice *dev, unsigned offset) 2515915a2adSSimon Glass { 2525915a2adSSimon Glass struct gpio_bank *bank = dev_get_priv(dev); 2535915a2adSSimon Glass 2545915a2adSSimon Glass return _get_gpio_value(bank, offset); 2555915a2adSSimon Glass } 2565915a2adSSimon Glass 2575915a2adSSimon Glass /* write GPIO OUT value to pin 'gpio' */ 2585915a2adSSimon Glass static int omap_gpio_set_value(struct udevice *dev, unsigned offset, 2595915a2adSSimon Glass int value) 2605915a2adSSimon Glass { 2615915a2adSSimon Glass struct gpio_bank *bank = dev_get_priv(dev); 2625915a2adSSimon Glass 2635915a2adSSimon Glass _set_gpio_dataout(bank, offset, value); 2645915a2adSSimon Glass 2655915a2adSSimon Glass return 0; 2665915a2adSSimon Glass } 2675915a2adSSimon Glass 2685915a2adSSimon Glass static int omap_gpio_get_function(struct udevice *dev, unsigned offset) 2695915a2adSSimon Glass { 2705915a2adSSimon Glass struct gpio_bank *bank = dev_get_priv(dev); 2715915a2adSSimon Glass 2725915a2adSSimon Glass /* GPIOF_FUNC is not implemented yet */ 27326c0472cSAxel Lin if (_get_gpio_direction(bank, offset) == OMAP_GPIO_DIR_OUT) 2745915a2adSSimon Glass return GPIOF_OUTPUT; 2755915a2adSSimon Glass else 2765915a2adSSimon Glass return GPIOF_INPUT; 2775915a2adSSimon Glass } 2785915a2adSSimon Glass 2795915a2adSSimon Glass static const struct dm_gpio_ops gpio_omap_ops = { 2805915a2adSSimon Glass .direction_input = omap_gpio_direction_input, 2815915a2adSSimon Glass .direction_output = omap_gpio_direction_output, 2825915a2adSSimon Glass .get_value = omap_gpio_get_value, 2835915a2adSSimon Glass .set_value = omap_gpio_set_value, 2845915a2adSSimon Glass .get_function = omap_gpio_get_function, 2855915a2adSSimon Glass }; 2865915a2adSSimon Glass 2875915a2adSSimon Glass static int omap_gpio_probe(struct udevice *dev) 2885915a2adSSimon Glass { 2895915a2adSSimon Glass struct gpio_bank *bank = dev_get_priv(dev); 2905915a2adSSimon Glass struct omap_gpio_platdata *plat = dev_get_platdata(dev); 291e564f054SSimon Glass struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 2925915a2adSSimon Glass 293*0a9e3405STom Rini uc_priv->bank_name = plat->port_name; 2945915a2adSSimon Glass uc_priv->gpio_count = GPIO_PER_BANK; 2955915a2adSSimon Glass bank->base = (void *)plat->base; 2965915a2adSSimon Glass 2975915a2adSSimon Glass return 0; 2985915a2adSSimon Glass } 2995915a2adSSimon Glass 300*0a9e3405STom Rini static int omap_gpio_bind(struct udevice *dev) 301*0a9e3405STom Rini { 302*0a9e3405STom Rini struct omap_gpio_platdata *plat = dev->platdata; 303*0a9e3405STom Rini fdt_addr_t base_addr; 304*0a9e3405STom Rini 305*0a9e3405STom Rini if (plat) 306*0a9e3405STom Rini return 0; 307*0a9e3405STom Rini 308*0a9e3405STom Rini base_addr = dev_get_addr(dev); 309*0a9e3405STom Rini if (base_addr == FDT_ADDR_T_NONE) 310*0a9e3405STom Rini return -ENODEV; 311*0a9e3405STom Rini 312*0a9e3405STom Rini /* 313*0a9e3405STom Rini * TODO: 314*0a9e3405STom Rini * When every board is converted to driver model and DT is 315*0a9e3405STom Rini * supported, this can be done by auto-alloc feature, but 316*0a9e3405STom Rini * not using calloc to alloc memory for platdata. 317*0a9e3405STom Rini */ 318*0a9e3405STom Rini plat = calloc(1, sizeof(*plat)); 319*0a9e3405STom Rini if (!plat) 320*0a9e3405STom Rini return -ENOMEM; 321*0a9e3405STom Rini 322*0a9e3405STom Rini plat->base = base_addr; 323*0a9e3405STom Rini plat->port_name = fdt_get_name(gd->fdt_blob, dev->of_offset, NULL); 324*0a9e3405STom Rini dev->platdata = plat; 325*0a9e3405STom Rini 326*0a9e3405STom Rini return 0; 327*0a9e3405STom Rini } 328*0a9e3405STom Rini 329*0a9e3405STom Rini static const struct udevice_id omap_gpio_ids[] = { 330*0a9e3405STom Rini { .compatible = "ti,omap3-gpio" }, 331*0a9e3405STom Rini { .compatible = "ti,omap4-gpio" }, 332*0a9e3405STom Rini { .compatible = "ti,am4372-gpio" }, 333*0a9e3405STom Rini { } 334*0a9e3405STom Rini }; 335*0a9e3405STom Rini 3365915a2adSSimon Glass U_BOOT_DRIVER(gpio_omap) = { 3375915a2adSSimon Glass .name = "gpio_omap", 3385915a2adSSimon Glass .id = UCLASS_GPIO, 3395915a2adSSimon Glass .ops = &gpio_omap_ops, 340*0a9e3405STom Rini .of_match = omap_gpio_ids, 341*0a9e3405STom Rini .bind = omap_gpio_bind, 3425915a2adSSimon Glass .probe = omap_gpio_probe, 3435915a2adSSimon Glass .priv_auto_alloc_size = sizeof(struct gpio_bank), 3445915a2adSSimon Glass }; 3455915a2adSSimon Glass 3465915a2adSSimon Glass #endif /* CONFIG_DM_GPIO */ 347