1abce2c62SIan Campbell /* 2abce2c62SIan Campbell * (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net> 3abce2c62SIan Campbell * 4abce2c62SIan Campbell * Based on earlier arch/arm/cpu/armv7/sunxi/gpio.c: 5abce2c62SIan Campbell * 6abce2c62SIan Campbell * (C) Copyright 2007-2011 7abce2c62SIan Campbell * Allwinner Technology Co., Ltd. <www.allwinnertech.com> 8abce2c62SIan Campbell * Tom Cubie <tangliang@allwinnertech.com> 9abce2c62SIan Campbell * 10abce2c62SIan Campbell * SPDX-License-Identifier: GPL-2.0+ 11abce2c62SIan Campbell */ 12abce2c62SIan Campbell 13abce2c62SIan Campbell #include <common.h> 147aa97485SSimon Glass #include <dm.h> 157aa97485SSimon Glass #include <errno.h> 167aa97485SSimon Glass #include <fdtdec.h> 177aa97485SSimon Glass #include <malloc.h> 182fcf033dSHans de Goede #include <asm/arch/gpio.h> 19abce2c62SIan Campbell #include <asm/io.h> 20abce2c62SIan Campbell #include <asm/gpio.h> 217aa97485SSimon Glass #include <dm/device-internal.h> 22abce2c62SIan Campbell 237aa97485SSimon Glass DECLARE_GLOBAL_DATA_PTR; 247aa97485SSimon Glass 257aa97485SSimon Glass #define SUNXI_GPIOS_PER_BANK SUNXI_GPIO_A_NR 267aa97485SSimon Glass 277aa97485SSimon Glass struct sunxi_gpio_platdata { 287aa97485SSimon Glass struct sunxi_gpio *regs; 297aa97485SSimon Glass const char *bank_name; /* Name of bank, e.g. "B" */ 307aa97485SSimon Glass int gpio_count; 317aa97485SSimon Glass }; 327aa97485SSimon Glass 337aa97485SSimon Glass #ifndef CONFIG_DM_GPIO 34abce2c62SIan Campbell static int sunxi_gpio_output(u32 pin, u32 val) 35abce2c62SIan Campbell { 36abce2c62SIan Campbell u32 dat; 37abce2c62SIan Campbell u32 bank = GPIO_BANK(pin); 38abce2c62SIan Campbell u32 num = GPIO_NUM(pin); 39abce2c62SIan Campbell struct sunxi_gpio *pio = BANK_TO_GPIO(bank); 40abce2c62SIan Campbell 41abce2c62SIan Campbell dat = readl(&pio->dat); 42abce2c62SIan Campbell if (val) 43abce2c62SIan Campbell dat |= 0x1 << num; 44abce2c62SIan Campbell else 45abce2c62SIan Campbell dat &= ~(0x1 << num); 46abce2c62SIan Campbell 47abce2c62SIan Campbell writel(dat, &pio->dat); 48abce2c62SIan Campbell 49abce2c62SIan Campbell return 0; 50abce2c62SIan Campbell } 51abce2c62SIan Campbell 52abce2c62SIan Campbell static int sunxi_gpio_input(u32 pin) 53abce2c62SIan Campbell { 54abce2c62SIan Campbell u32 dat; 55abce2c62SIan Campbell u32 bank = GPIO_BANK(pin); 56abce2c62SIan Campbell u32 num = GPIO_NUM(pin); 57abce2c62SIan Campbell struct sunxi_gpio *pio = BANK_TO_GPIO(bank); 58abce2c62SIan Campbell 59abce2c62SIan Campbell dat = readl(&pio->dat); 60abce2c62SIan Campbell dat >>= num; 61abce2c62SIan Campbell 62abce2c62SIan Campbell return dat & 0x1; 63abce2c62SIan Campbell } 64abce2c62SIan Campbell 65abce2c62SIan Campbell int gpio_request(unsigned gpio, const char *label) 66abce2c62SIan Campbell { 67abce2c62SIan Campbell return 0; 68abce2c62SIan Campbell } 69abce2c62SIan Campbell 70abce2c62SIan Campbell int gpio_free(unsigned gpio) 71abce2c62SIan Campbell { 72abce2c62SIan Campbell return 0; 73abce2c62SIan Campbell } 74abce2c62SIan Campbell 75abce2c62SIan Campbell int gpio_direction_input(unsigned gpio) 76abce2c62SIan Campbell { 772fcf033dSHans de Goede #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO 786c727e09SHans de Goede if (gpio >= SUNXI_GPIO_AXP0_START) 7912ce1553SHans de Goede return axp_gpio_direction_input(NULL, gpio - SUNXI_GPIO_AXP0_START); 806c727e09SHans de Goede #endif 81abce2c62SIan Campbell sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT); 82abce2c62SIan Campbell 83b0c4ae1aSAxel Lin return 0; 84abce2c62SIan Campbell } 85abce2c62SIan Campbell 86abce2c62SIan Campbell int gpio_direction_output(unsigned gpio, int value) 87abce2c62SIan Campbell { 882fcf033dSHans de Goede #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO 896c727e09SHans de Goede if (gpio >= SUNXI_GPIO_AXP0_START) 9012ce1553SHans de Goede return axp_gpio_direction_output(NULL, gpio - SUNXI_GPIO_AXP0_START, 916c727e09SHans de Goede value); 926c727e09SHans de Goede #endif 93abce2c62SIan Campbell sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT); 94abce2c62SIan Campbell 95abce2c62SIan Campbell return sunxi_gpio_output(gpio, value); 96abce2c62SIan Campbell } 97abce2c62SIan Campbell 98abce2c62SIan Campbell int gpio_get_value(unsigned gpio) 99abce2c62SIan Campbell { 1002fcf033dSHans de Goede #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO 1016c727e09SHans de Goede if (gpio >= SUNXI_GPIO_AXP0_START) 10212ce1553SHans de Goede return axp_gpio_get_value(NULL, gpio - SUNXI_GPIO_AXP0_START); 1036c727e09SHans de Goede #endif 104abce2c62SIan Campbell return sunxi_gpio_input(gpio); 105abce2c62SIan Campbell } 106abce2c62SIan Campbell 107abce2c62SIan Campbell int gpio_set_value(unsigned gpio, int value) 108abce2c62SIan Campbell { 1092fcf033dSHans de Goede #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO 1106c727e09SHans de Goede if (gpio >= SUNXI_GPIO_AXP0_START) 11112ce1553SHans de Goede return axp_gpio_set_value(NULL, gpio - SUNXI_GPIO_AXP0_START, value); 1126c727e09SHans de Goede #endif 113abce2c62SIan Campbell return sunxi_gpio_output(gpio, value); 114abce2c62SIan Campbell } 115abce2c62SIan Campbell 116abce2c62SIan Campbell int sunxi_name_to_gpio(const char *name) 117abce2c62SIan Campbell { 118abce2c62SIan Campbell int group = 0; 119abce2c62SIan Campbell int groupsize = 9 * 32; 120abce2c62SIan Campbell long pin; 121abce2c62SIan Campbell char *eptr; 1226c727e09SHans de Goede 1232fcf033dSHans de Goede #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO 1246c727e09SHans de Goede if (strncasecmp(name, "AXP0-", 5) == 0) { 1256c727e09SHans de Goede name += 5; 126f7c7ab63SPaul Kocialkowski if (strcmp(name, "VBUS-DETECT") == 0) 127f7c7ab63SPaul Kocialkowski return SUNXI_GPIO_AXP0_START + 128f7c7ab63SPaul Kocialkowski SUNXI_GPIO_AXP0_VBUS_DETECT; 129f7c7ab63SPaul Kocialkowski if (strcmp(name, "VBUS-ENABLE") == 0) 130f7c7ab63SPaul Kocialkowski return SUNXI_GPIO_AXP0_START + 131f7c7ab63SPaul Kocialkowski SUNXI_GPIO_AXP0_VBUS_ENABLE; 1326c727e09SHans de Goede pin = simple_strtol(name, &eptr, 10); 1336c727e09SHans de Goede if (!*name || *eptr) 1346c727e09SHans de Goede return -1; 1356c727e09SHans de Goede return SUNXI_GPIO_AXP0_START + pin; 1366c727e09SHans de Goede } 1376c727e09SHans de Goede #endif 138abce2c62SIan Campbell if (*name == 'P' || *name == 'p') 139abce2c62SIan Campbell name++; 140abce2c62SIan Campbell if (*name >= 'A') { 141abce2c62SIan Campbell group = *name - (*name > 'a' ? 'a' : 'A'); 142abce2c62SIan Campbell groupsize = 32; 143abce2c62SIan Campbell name++; 144abce2c62SIan Campbell } 145abce2c62SIan Campbell 146abce2c62SIan Campbell pin = simple_strtol(name, &eptr, 10); 147abce2c62SIan Campbell if (!*name || *eptr) 148abce2c62SIan Campbell return -1; 149abce2c62SIan Campbell if (pin < 0 || pin > groupsize || group >= 9) 150abce2c62SIan Campbell return -1; 151abce2c62SIan Campbell return group * 32 + pin; 152abce2c62SIan Campbell } 1537aa97485SSimon Glass #endif 1547aa97485SSimon Glass 155746c087bSHans de Goede int sunxi_name_to_gpio_bank(const char *name) 156746c087bSHans de Goede { 157746c087bSHans de Goede int group = 0; 158746c087bSHans de Goede 159746c087bSHans de Goede if (*name == 'P' || *name == 'p') 160746c087bSHans de Goede name++; 161746c087bSHans de Goede if (*name >= 'A') { 162746c087bSHans de Goede group = *name - (*name > 'a' ? 'a' : 'A'); 163746c087bSHans de Goede return group; 164746c087bSHans de Goede } 165746c087bSHans de Goede 166746c087bSHans de Goede return -1; 167746c087bSHans de Goede } 168746c087bSHans de Goede 1697aa97485SSimon Glass #ifdef CONFIG_DM_GPIO 170a5ab8838SSimon Glass /* TODO(sjg@chromium.org): Remove this function and use device tree */ 171a5ab8838SSimon Glass int sunxi_name_to_gpio(const char *name) 172a5ab8838SSimon Glass { 173a5ab8838SSimon Glass unsigned int gpio; 174a5ab8838SSimon Glass int ret; 175*f9b7a04bSHans de Goede #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO 176*f9b7a04bSHans de Goede char lookup[8]; 177a5ab8838SSimon Glass 178*f9b7a04bSHans de Goede if (strcasecmp(name, "AXP0-VBUS-DETECT") == 0) { 179*f9b7a04bSHans de Goede sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d", 180*f9b7a04bSHans de Goede SUNXI_GPIO_AXP0_VBUS_DETECT); 181*f9b7a04bSHans de Goede name = lookup; 182*f9b7a04bSHans de Goede } else if (strcasecmp(name, "AXP0-VBUS-ENABLE") == 0) { 183*f9b7a04bSHans de Goede sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d", 184*f9b7a04bSHans de Goede SUNXI_GPIO_AXP0_VBUS_ENABLE); 185*f9b7a04bSHans de Goede name = lookup; 186*f9b7a04bSHans de Goede } 187*f9b7a04bSHans de Goede #endif 188a5ab8838SSimon Glass ret = gpio_lookup_name(name, NULL, NULL, &gpio); 189a5ab8838SSimon Glass 190a5ab8838SSimon Glass return ret ? ret : gpio; 191a5ab8838SSimon Glass } 192a5ab8838SSimon Glass 1937aa97485SSimon Glass static int sunxi_gpio_direction_input(struct udevice *dev, unsigned offset) 1947aa97485SSimon Glass { 1957aa97485SSimon Glass struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); 1967aa97485SSimon Glass 1977aa97485SSimon Glass sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT); 1987aa97485SSimon Glass 1997aa97485SSimon Glass return 0; 2007aa97485SSimon Glass } 2017aa97485SSimon Glass 2027aa97485SSimon Glass static int sunxi_gpio_direction_output(struct udevice *dev, unsigned offset, 2037aa97485SSimon Glass int value) 2047aa97485SSimon Glass { 2057aa97485SSimon Glass struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); 2067aa97485SSimon Glass u32 num = GPIO_NUM(offset); 2077aa97485SSimon Glass 2087aa97485SSimon Glass sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT); 2097aa97485SSimon Glass clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0); 2107aa97485SSimon Glass 2117aa97485SSimon Glass return 0; 2127aa97485SSimon Glass } 2137aa97485SSimon Glass 2147aa97485SSimon Glass static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset) 2157aa97485SSimon Glass { 2167aa97485SSimon Glass struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); 2177aa97485SSimon Glass u32 num = GPIO_NUM(offset); 2187aa97485SSimon Glass unsigned dat; 2197aa97485SSimon Glass 2207aa97485SSimon Glass dat = readl(&plat->regs->dat); 2217aa97485SSimon Glass dat >>= num; 2227aa97485SSimon Glass 2237aa97485SSimon Glass return dat & 0x1; 2247aa97485SSimon Glass } 2257aa97485SSimon Glass 2267aa97485SSimon Glass static int sunxi_gpio_set_value(struct udevice *dev, unsigned offset, 2277aa97485SSimon Glass int value) 2287aa97485SSimon Glass { 2297aa97485SSimon Glass struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); 2307aa97485SSimon Glass u32 num = GPIO_NUM(offset); 2317aa97485SSimon Glass 2327aa97485SSimon Glass clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0); 2337aa97485SSimon Glass return 0; 2347aa97485SSimon Glass } 2357aa97485SSimon Glass 2367aa97485SSimon Glass static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset) 2377aa97485SSimon Glass { 2387aa97485SSimon Glass struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); 2397aa97485SSimon Glass int func; 2407aa97485SSimon Glass 2417aa97485SSimon Glass func = sunxi_gpio_get_cfgbank(plat->regs, offset); 2427aa97485SSimon Glass if (func == SUNXI_GPIO_OUTPUT) 2437aa97485SSimon Glass return GPIOF_OUTPUT; 2447aa97485SSimon Glass else if (func == SUNXI_GPIO_INPUT) 2457aa97485SSimon Glass return GPIOF_INPUT; 2467aa97485SSimon Glass else 2477aa97485SSimon Glass return GPIOF_FUNC; 2487aa97485SSimon Glass } 2497aa97485SSimon Glass 2507aa97485SSimon Glass static const struct dm_gpio_ops gpio_sunxi_ops = { 2517aa97485SSimon Glass .direction_input = sunxi_gpio_direction_input, 2527aa97485SSimon Glass .direction_output = sunxi_gpio_direction_output, 2537aa97485SSimon Glass .get_value = sunxi_gpio_get_value, 2547aa97485SSimon Glass .set_value = sunxi_gpio_set_value, 2557aa97485SSimon Glass .get_function = sunxi_gpio_get_function, 2567aa97485SSimon Glass }; 2577aa97485SSimon Glass 2587aa97485SSimon Glass /** 2597aa97485SSimon Glass * Returns the name of a GPIO bank 2607aa97485SSimon Glass * 2617aa97485SSimon Glass * GPIO banks are named A, B, C, ... 2627aa97485SSimon Glass * 2637aa97485SSimon Glass * @bank: Bank number (0, 1..n-1) 2647aa97485SSimon Glass * @return allocated string containing the name 2657aa97485SSimon Glass */ 2667aa97485SSimon Glass static char *gpio_bank_name(int bank) 2677aa97485SSimon Glass { 2687aa97485SSimon Glass char *name; 2697aa97485SSimon Glass 27007ce60f3SSimon Glass name = malloc(3); 2717aa97485SSimon Glass if (name) { 27207ce60f3SSimon Glass name[0] = 'P'; 27307ce60f3SSimon Glass name[1] = 'A' + bank; 27407ce60f3SSimon Glass name[2] = '\0'; 2757aa97485SSimon Glass } 2767aa97485SSimon Glass 2777aa97485SSimon Glass return name; 2787aa97485SSimon Glass } 2797aa97485SSimon Glass 2807aa97485SSimon Glass static int gpio_sunxi_probe(struct udevice *dev) 2817aa97485SSimon Glass { 2827aa97485SSimon Glass struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); 283e564f054SSimon Glass struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 2847aa97485SSimon Glass 2857aa97485SSimon Glass /* Tell the uclass how many GPIOs we have */ 2867aa97485SSimon Glass if (plat) { 2877aa97485SSimon Glass uc_priv->gpio_count = plat->gpio_count; 2887aa97485SSimon Glass uc_priv->bank_name = plat->bank_name; 2897aa97485SSimon Glass } 2907aa97485SSimon Glass 2917aa97485SSimon Glass return 0; 2927aa97485SSimon Glass } 2937aa97485SSimon Glass /** 2947aa97485SSimon Glass * We have a top-level GPIO device with no actual GPIOs. It has a child 2957aa97485SSimon Glass * device for each Sunxi bank. 2967aa97485SSimon Glass */ 2977aa97485SSimon Glass static int gpio_sunxi_bind(struct udevice *parent) 2987aa97485SSimon Glass { 2997aa97485SSimon Glass struct sunxi_gpio_platdata *plat = parent->platdata; 3007aa97485SSimon Glass struct sunxi_gpio_reg *ctlr; 3017aa97485SSimon Glass int bank; 3027aa97485SSimon Glass int ret; 3037aa97485SSimon Glass 3047aa97485SSimon Glass /* If this is a child device, there is nothing to do here */ 3057aa97485SSimon Glass if (plat) 3067aa97485SSimon Glass return 0; 3077aa97485SSimon Glass 3087aa97485SSimon Glass ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr(gd->fdt_blob, 3097aa97485SSimon Glass parent->of_offset, "reg"); 3107aa97485SSimon Glass for (bank = 0; bank < SUNXI_GPIO_BANKS; bank++) { 3117aa97485SSimon Glass struct sunxi_gpio_platdata *plat; 3127aa97485SSimon Glass struct udevice *dev; 3137aa97485SSimon Glass 3147aa97485SSimon Glass plat = calloc(1, sizeof(*plat)); 3157aa97485SSimon Glass if (!plat) 3167aa97485SSimon Glass return -ENOMEM; 3177aa97485SSimon Glass plat->regs = &ctlr->gpio_bank[bank]; 3187aa97485SSimon Glass plat->bank_name = gpio_bank_name(bank); 3197aa97485SSimon Glass plat->gpio_count = SUNXI_GPIOS_PER_BANK; 3207aa97485SSimon Glass 3217aa97485SSimon Glass ret = device_bind(parent, parent->driver, 3227aa97485SSimon Glass plat->bank_name, plat, -1, &dev); 3237aa97485SSimon Glass if (ret) 3247aa97485SSimon Glass return ret; 3257aa97485SSimon Glass dev->of_offset = parent->of_offset; 3267aa97485SSimon Glass } 3277aa97485SSimon Glass 3287aa97485SSimon Glass return 0; 3297aa97485SSimon Glass } 3307aa97485SSimon Glass 3317aa97485SSimon Glass static const struct udevice_id sunxi_gpio_ids[] = { 33211d52a9dSHans de Goede { .compatible = "allwinner,sun4i-a10-pinctrl" }, 33311d52a9dSHans de Goede { .compatible = "allwinner,sun5i-a10s-pinctrl" }, 33411d52a9dSHans de Goede { .compatible = "allwinner,sun5i-a13-pinctrl" }, 33511d52a9dSHans de Goede { .compatible = "allwinner,sun6i-a31-pinctrl" }, 33611d52a9dSHans de Goede { .compatible = "allwinner,sun6i-a31s-pinctrl" }, 3377aa97485SSimon Glass { .compatible = "allwinner,sun7i-a20-pinctrl" }, 33811d52a9dSHans de Goede { .compatible = "allwinner,sun8i-a23-pinctrl" }, 33911d52a9dSHans de Goede { .compatible = "allwinner,sun9i-a80-pinctrl" }, 3407aa97485SSimon Glass { } 3417aa97485SSimon Glass }; 3427aa97485SSimon Glass 3437aa97485SSimon Glass U_BOOT_DRIVER(gpio_sunxi) = { 3447aa97485SSimon Glass .name = "gpio_sunxi", 3457aa97485SSimon Glass .id = UCLASS_GPIO, 3467aa97485SSimon Glass .ops = &gpio_sunxi_ops, 3477aa97485SSimon Glass .of_match = sunxi_gpio_ids, 3487aa97485SSimon Glass .bind = gpio_sunxi_bind, 3497aa97485SSimon Glass .probe = gpio_sunxi_probe, 3507aa97485SSimon Glass }; 3517aa97485SSimon Glass #endif 352