1*b9a66b63SMasahiro Yamada /* 2*b9a66b63SMasahiro Yamada * Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com> 3*b9a66b63SMasahiro Yamada * 4*b9a66b63SMasahiro Yamada * SPDX-License-Identifier: GPL-2.0+ 5*b9a66b63SMasahiro Yamada */ 6*b9a66b63SMasahiro Yamada 7*b9a66b63SMasahiro Yamada #include <common.h> 8*b9a66b63SMasahiro Yamada #include <dm/device.h> 9*b9a66b63SMasahiro Yamada #include <mapmem.h> 10*b9a66b63SMasahiro Yamada #include <linux/bitops.h> 11*b9a66b63SMasahiro Yamada #include <linux/io.h> 12*b9a66b63SMasahiro Yamada #include <asm/errno.h> 13*b9a66b63SMasahiro Yamada #include <asm/gpio.h> 14*b9a66b63SMasahiro Yamada 15*b9a66b63SMasahiro Yamada #define UNIPHIER_GPIO_PORTS_PER_BANK 8 16*b9a66b63SMasahiro Yamada 17*b9a66b63SMasahiro Yamada #define UNIPHIER_GPIO_REG_DATA 0 /* data */ 18*b9a66b63SMasahiro Yamada #define UNIPHIER_GPIO_REG_DIR 4 /* direction (1:in, 0:out) */ 19*b9a66b63SMasahiro Yamada 20*b9a66b63SMasahiro Yamada struct uniphier_gpio_priv { 21*b9a66b63SMasahiro Yamada void __iomem *base; 22*b9a66b63SMasahiro Yamada char bank_name[16]; 23*b9a66b63SMasahiro Yamada }; 24*b9a66b63SMasahiro Yamada 25*b9a66b63SMasahiro Yamada static void uniphier_gpio_offset_write(struct udevice *dev, unsigned offset, 26*b9a66b63SMasahiro Yamada unsigned reg, int value) 27*b9a66b63SMasahiro Yamada { 28*b9a66b63SMasahiro Yamada struct uniphier_gpio_priv *priv = dev_get_priv(dev); 29*b9a66b63SMasahiro Yamada u32 tmp; 30*b9a66b63SMasahiro Yamada 31*b9a66b63SMasahiro Yamada tmp = readl(priv->base + reg); 32*b9a66b63SMasahiro Yamada if (value) 33*b9a66b63SMasahiro Yamada tmp |= BIT(offset); 34*b9a66b63SMasahiro Yamada else 35*b9a66b63SMasahiro Yamada tmp &= ~BIT(offset); 36*b9a66b63SMasahiro Yamada writel(tmp, priv->base + reg); 37*b9a66b63SMasahiro Yamada } 38*b9a66b63SMasahiro Yamada 39*b9a66b63SMasahiro Yamada static int uniphier_gpio_offset_read(struct udevice *dev, unsigned offset, 40*b9a66b63SMasahiro Yamada unsigned reg) 41*b9a66b63SMasahiro Yamada { 42*b9a66b63SMasahiro Yamada struct uniphier_gpio_priv *priv = dev_get_priv(dev); 43*b9a66b63SMasahiro Yamada 44*b9a66b63SMasahiro Yamada return !!(readl(priv->base + reg) & BIT(offset)); 45*b9a66b63SMasahiro Yamada } 46*b9a66b63SMasahiro Yamada 47*b9a66b63SMasahiro Yamada static int uniphier_gpio_direction_input(struct udevice *dev, unsigned offset) 48*b9a66b63SMasahiro Yamada { 49*b9a66b63SMasahiro Yamada uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_REG_DIR, 1); 50*b9a66b63SMasahiro Yamada 51*b9a66b63SMasahiro Yamada return 0; 52*b9a66b63SMasahiro Yamada } 53*b9a66b63SMasahiro Yamada 54*b9a66b63SMasahiro Yamada static int uniphier_gpio_direction_output(struct udevice *dev, unsigned offset, 55*b9a66b63SMasahiro Yamada int value) 56*b9a66b63SMasahiro Yamada { 57*b9a66b63SMasahiro Yamada uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_REG_DATA, value); 58*b9a66b63SMasahiro Yamada uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_REG_DIR, 0); 59*b9a66b63SMasahiro Yamada 60*b9a66b63SMasahiro Yamada return 0; 61*b9a66b63SMasahiro Yamada } 62*b9a66b63SMasahiro Yamada 63*b9a66b63SMasahiro Yamada static int uniphier_gpio_get_value(struct udevice *dev, unsigned offset) 64*b9a66b63SMasahiro Yamada { 65*b9a66b63SMasahiro Yamada return uniphier_gpio_offset_read(dev, offset, UNIPHIER_GPIO_REG_DATA); 66*b9a66b63SMasahiro Yamada } 67*b9a66b63SMasahiro Yamada 68*b9a66b63SMasahiro Yamada static int uniphier_gpio_set_value(struct udevice *dev, unsigned offset, 69*b9a66b63SMasahiro Yamada int value) 70*b9a66b63SMasahiro Yamada { 71*b9a66b63SMasahiro Yamada uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_REG_DATA, value); 72*b9a66b63SMasahiro Yamada 73*b9a66b63SMasahiro Yamada return 0; 74*b9a66b63SMasahiro Yamada } 75*b9a66b63SMasahiro Yamada 76*b9a66b63SMasahiro Yamada static int uniphier_gpio_get_function(struct udevice *dev, unsigned offset) 77*b9a66b63SMasahiro Yamada { 78*b9a66b63SMasahiro Yamada return uniphier_gpio_offset_read(dev, offset, UNIPHIER_GPIO_REG_DIR) ? 79*b9a66b63SMasahiro Yamada GPIOF_INPUT : GPIOF_OUTPUT; 80*b9a66b63SMasahiro Yamada } 81*b9a66b63SMasahiro Yamada 82*b9a66b63SMasahiro Yamada static const struct dm_gpio_ops uniphier_gpio_ops = { 83*b9a66b63SMasahiro Yamada .direction_input = uniphier_gpio_direction_input, 84*b9a66b63SMasahiro Yamada .direction_output = uniphier_gpio_direction_output, 85*b9a66b63SMasahiro Yamada .get_value = uniphier_gpio_get_value, 86*b9a66b63SMasahiro Yamada .set_value = uniphier_gpio_set_value, 87*b9a66b63SMasahiro Yamada .get_function = uniphier_gpio_get_function, 88*b9a66b63SMasahiro Yamada }; 89*b9a66b63SMasahiro Yamada 90*b9a66b63SMasahiro Yamada static int uniphier_gpio_probe(struct udevice *dev) 91*b9a66b63SMasahiro Yamada { 92*b9a66b63SMasahiro Yamada struct uniphier_gpio_priv *priv = dev_get_priv(dev); 93*b9a66b63SMasahiro Yamada struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 94*b9a66b63SMasahiro Yamada DECLARE_GLOBAL_DATA_PTR; 95*b9a66b63SMasahiro Yamada fdt_addr_t addr; 96*b9a66b63SMasahiro Yamada fdt_size_t size; 97*b9a66b63SMasahiro Yamada unsigned int tmp; 98*b9a66b63SMasahiro Yamada 99*b9a66b63SMasahiro Yamada addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", 100*b9a66b63SMasahiro Yamada &size); 101*b9a66b63SMasahiro Yamada if (addr == FDT_ADDR_T_NONE) 102*b9a66b63SMasahiro Yamada return -EINVAL; 103*b9a66b63SMasahiro Yamada 104*b9a66b63SMasahiro Yamada priv->base = map_sysmem(addr, size); 105*b9a66b63SMasahiro Yamada if (!priv->base) 106*b9a66b63SMasahiro Yamada return -ENOMEM; 107*b9a66b63SMasahiro Yamada 108*b9a66b63SMasahiro Yamada uc_priv->gpio_count = UNIPHIER_GPIO_PORTS_PER_BANK; 109*b9a66b63SMasahiro Yamada 110*b9a66b63SMasahiro Yamada tmp = (addr & 0xfff); 111*b9a66b63SMasahiro Yamada 112*b9a66b63SMasahiro Yamada /* Unfortunately, there is a register hole at offset 0x90-0x9f. */ 113*b9a66b63SMasahiro Yamada if (tmp > 0x90) 114*b9a66b63SMasahiro Yamada tmp -= 0x10; 115*b9a66b63SMasahiro Yamada 116*b9a66b63SMasahiro Yamada snprintf(priv->bank_name, sizeof(priv->bank_name) - 1, 117*b9a66b63SMasahiro Yamada "port%d-", (tmp - 8) / 8); 118*b9a66b63SMasahiro Yamada 119*b9a66b63SMasahiro Yamada uc_priv->bank_name = priv->bank_name; 120*b9a66b63SMasahiro Yamada 121*b9a66b63SMasahiro Yamada return 0; 122*b9a66b63SMasahiro Yamada } 123*b9a66b63SMasahiro Yamada 124*b9a66b63SMasahiro Yamada static int uniphier_gpio_remove(struct udevice *dev) 125*b9a66b63SMasahiro Yamada { 126*b9a66b63SMasahiro Yamada struct uniphier_gpio_priv *priv = dev_get_priv(dev); 127*b9a66b63SMasahiro Yamada 128*b9a66b63SMasahiro Yamada unmap_sysmem(priv->base); 129*b9a66b63SMasahiro Yamada 130*b9a66b63SMasahiro Yamada return 0; 131*b9a66b63SMasahiro Yamada } 132*b9a66b63SMasahiro Yamada 133*b9a66b63SMasahiro Yamada /* .data = the number of GPIO banks */ 134*b9a66b63SMasahiro Yamada static const struct udevice_id uniphier_gpio_match[] = { 135*b9a66b63SMasahiro Yamada { .compatible = "socionext,uniphier-gpio" }, 136*b9a66b63SMasahiro Yamada { /* sentinel */ } 137*b9a66b63SMasahiro Yamada }; 138*b9a66b63SMasahiro Yamada 139*b9a66b63SMasahiro Yamada U_BOOT_DRIVER(uniphier_gpio) = { 140*b9a66b63SMasahiro Yamada .name = "uniphier_gpio", 141*b9a66b63SMasahiro Yamada .id = UCLASS_GPIO, 142*b9a66b63SMasahiro Yamada .of_match = uniphier_gpio_match, 143*b9a66b63SMasahiro Yamada .probe = uniphier_gpio_probe, 144*b9a66b63SMasahiro Yamada .remove = uniphier_gpio_remove, 145*b9a66b63SMasahiro Yamada .priv_auto_alloc_size = sizeof(struct uniphier_gpio_priv), 146*b9a66b63SMasahiro Yamada .ops = &uniphier_gpio_ops, 147*b9a66b63SMasahiro Yamada }; 148