1b9a66b63SMasahiro Yamada /* 2*c5fb1c25SMasahiro Yamada * Copyright (C) 2016-2017 Socionext Inc. 34e3d8406SMasahiro Yamada * Author: Masahiro Yamada <yamada.masahiro@socionext.com> 4b9a66b63SMasahiro Yamada * 5b9a66b63SMasahiro Yamada * SPDX-License-Identifier: GPL-2.0+ 6b9a66b63SMasahiro Yamada */ 7b9a66b63SMasahiro Yamada 8b9a66b63SMasahiro Yamada #include <common.h> 99d922450SSimon Glass #include <dm.h> 10b9a66b63SMasahiro Yamada #include <linux/bitops.h> 11b9a66b63SMasahiro Yamada #include <linux/io.h> 12bc82a131SMasahiro Yamada #include <linux/sizes.h> 131221ce45SMasahiro Yamada #include <linux/errno.h> 14*c5fb1c25SMasahiro Yamada #include <asm/global_data.h> 15b9a66b63SMasahiro Yamada #include <asm/gpio.h> 16b9a66b63SMasahiro Yamada 17*c5fb1c25SMasahiro Yamada #define UNIPHIER_GPIO_LINES_PER_BANK 8 18b9a66b63SMasahiro Yamada 19*c5fb1c25SMasahiro Yamada #define UNIPHIER_GPIO_PORT_DATA 0x0 /* data */ 20*c5fb1c25SMasahiro Yamada #define UNIPHIER_GPIO_PORT_DIR 0x4 /* direction (1:in, 0:out) */ 21*c5fb1c25SMasahiro Yamada #define UNIPHIER_GPIO_IRQ_EN 0x90 /* irq enable */ 22b9a66b63SMasahiro Yamada 23b9a66b63SMasahiro Yamada struct uniphier_gpio_priv { 24*c5fb1c25SMasahiro Yamada void __iomem *regs; 25b9a66b63SMasahiro Yamada }; 26b9a66b63SMasahiro Yamada 27*c5fb1c25SMasahiro Yamada static unsigned int uniphier_gpio_bank_to_reg(unsigned int bank) 28b9a66b63SMasahiro Yamada { 29*c5fb1c25SMasahiro Yamada unsigned int reg; 30*c5fb1c25SMasahiro Yamada 31*c5fb1c25SMasahiro Yamada reg = (bank + 1) * 8; 32*c5fb1c25SMasahiro Yamada 33*c5fb1c25SMasahiro Yamada /* 34*c5fb1c25SMasahiro Yamada * Unfortunately, the GPIO port registers are not contiguous because 35*c5fb1c25SMasahiro Yamada * offset 0x90-0x9f is used for IRQ. Add 0x10 when crossing the region. 36*c5fb1c25SMasahiro Yamada */ 37*c5fb1c25SMasahiro Yamada if (reg >= UNIPHIER_GPIO_IRQ_EN) 38*c5fb1c25SMasahiro Yamada reg += 0x10; 39*c5fb1c25SMasahiro Yamada 40*c5fb1c25SMasahiro Yamada return reg; 41*c5fb1c25SMasahiro Yamada } 42*c5fb1c25SMasahiro Yamada 43*c5fb1c25SMasahiro Yamada static void uniphier_gpio_get_bank_and_mask(unsigned int offset, 44*c5fb1c25SMasahiro Yamada unsigned int *bank, u32 *mask) 45*c5fb1c25SMasahiro Yamada { 46*c5fb1c25SMasahiro Yamada *bank = offset / UNIPHIER_GPIO_LINES_PER_BANK; 47*c5fb1c25SMasahiro Yamada *mask = BIT(offset % UNIPHIER_GPIO_LINES_PER_BANK); 48*c5fb1c25SMasahiro Yamada } 49*c5fb1c25SMasahiro Yamada 50*c5fb1c25SMasahiro Yamada static void uniphier_gpio_reg_update(struct uniphier_gpio_priv *priv, 51*c5fb1c25SMasahiro Yamada unsigned int reg, u32 mask, u32 val) 52*c5fb1c25SMasahiro Yamada { 53b9a66b63SMasahiro Yamada u32 tmp; 54b9a66b63SMasahiro Yamada 55*c5fb1c25SMasahiro Yamada tmp = readl(priv->regs + reg); 56*c5fb1c25SMasahiro Yamada tmp &= ~mask; 57*c5fb1c25SMasahiro Yamada tmp |= mask & val; 58*c5fb1c25SMasahiro Yamada writel(tmp, priv->regs + reg); 59b9a66b63SMasahiro Yamada } 60b9a66b63SMasahiro Yamada 61*c5fb1c25SMasahiro Yamada static void uniphier_gpio_bank_write(struct udevice *dev, unsigned int bank, 62*c5fb1c25SMasahiro Yamada unsigned int reg, u32 mask, u32 val) 63b9a66b63SMasahiro Yamada { 64b9a66b63SMasahiro Yamada struct uniphier_gpio_priv *priv = dev_get_priv(dev); 65b9a66b63SMasahiro Yamada 66*c5fb1c25SMasahiro Yamada if (!mask) 67*c5fb1c25SMasahiro Yamada return; 68*c5fb1c25SMasahiro Yamada 69*c5fb1c25SMasahiro Yamada uniphier_gpio_reg_update(priv, uniphier_gpio_bank_to_reg(bank) + reg, 70*c5fb1c25SMasahiro Yamada mask, val); 71b9a66b63SMasahiro Yamada } 72b9a66b63SMasahiro Yamada 73*c5fb1c25SMasahiro Yamada static void uniphier_gpio_offset_write(struct udevice *dev, unsigned int offset, 74*c5fb1c25SMasahiro Yamada unsigned int reg, int val) 75b9a66b63SMasahiro Yamada { 76*c5fb1c25SMasahiro Yamada unsigned int bank; 77*c5fb1c25SMasahiro Yamada u32 mask; 78b9a66b63SMasahiro Yamada 79*c5fb1c25SMasahiro Yamada uniphier_gpio_get_bank_and_mask(offset, &bank, &mask); 80*c5fb1c25SMasahiro Yamada 81*c5fb1c25SMasahiro Yamada uniphier_gpio_bank_write(dev, bank, reg, mask, val ? mask : 0); 82b9a66b63SMasahiro Yamada } 83b9a66b63SMasahiro Yamada 84*c5fb1c25SMasahiro Yamada static int uniphier_gpio_offset_read(struct udevice *dev, 85*c5fb1c25SMasahiro Yamada unsigned int offset, unsigned int reg) 86b9a66b63SMasahiro Yamada { 87*c5fb1c25SMasahiro Yamada struct uniphier_gpio_priv *priv = dev_get_priv(dev); 88*c5fb1c25SMasahiro Yamada unsigned int bank, reg_offset; 89*c5fb1c25SMasahiro Yamada u32 mask; 90b9a66b63SMasahiro Yamada 91*c5fb1c25SMasahiro Yamada uniphier_gpio_get_bank_and_mask(offset, &bank, &mask); 92*c5fb1c25SMasahiro Yamada reg_offset = uniphier_gpio_bank_to_reg(bank) + reg; 93*c5fb1c25SMasahiro Yamada 94*c5fb1c25SMasahiro Yamada return !!(readl(priv->regs + reg_offset) & mask); 95b9a66b63SMasahiro Yamada } 96b9a66b63SMasahiro Yamada 97*c5fb1c25SMasahiro Yamada static int uniphier_gpio_get_function(struct udevice *dev, unsigned int offset) 98b9a66b63SMasahiro Yamada { 99*c5fb1c25SMasahiro Yamada return uniphier_gpio_offset_read(dev, offset, UNIPHIER_GPIO_PORT_DIR) ? 100b9a66b63SMasahiro Yamada GPIOF_INPUT : GPIOF_OUTPUT; 101b9a66b63SMasahiro Yamada } 102b9a66b63SMasahiro Yamada 103*c5fb1c25SMasahiro Yamada static int uniphier_gpio_direction_input(struct udevice *dev, 104*c5fb1c25SMasahiro Yamada unsigned int offset) 105*c5fb1c25SMasahiro Yamada { 106*c5fb1c25SMasahiro Yamada uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_PORT_DIR, 1); 107*c5fb1c25SMasahiro Yamada 108*c5fb1c25SMasahiro Yamada return 0; 109*c5fb1c25SMasahiro Yamada } 110*c5fb1c25SMasahiro Yamada 111*c5fb1c25SMasahiro Yamada static int uniphier_gpio_direction_output(struct udevice *dev, 112*c5fb1c25SMasahiro Yamada unsigned int offset, int value) 113*c5fb1c25SMasahiro Yamada { 114*c5fb1c25SMasahiro Yamada uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_PORT_DATA, value); 115*c5fb1c25SMasahiro Yamada uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_PORT_DIR, 0); 116*c5fb1c25SMasahiro Yamada 117*c5fb1c25SMasahiro Yamada return 0; 118*c5fb1c25SMasahiro Yamada } 119*c5fb1c25SMasahiro Yamada 120*c5fb1c25SMasahiro Yamada static int uniphier_gpio_get_value(struct udevice *dev, unsigned int offset) 121*c5fb1c25SMasahiro Yamada { 122*c5fb1c25SMasahiro Yamada return uniphier_gpio_offset_read(dev, offset, UNIPHIER_GPIO_PORT_DATA); 123*c5fb1c25SMasahiro Yamada } 124*c5fb1c25SMasahiro Yamada 125*c5fb1c25SMasahiro Yamada static int uniphier_gpio_set_value(struct udevice *dev, 126*c5fb1c25SMasahiro Yamada unsigned int offset, int value) 127*c5fb1c25SMasahiro Yamada { 128*c5fb1c25SMasahiro Yamada uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_PORT_DATA, value); 129*c5fb1c25SMasahiro Yamada 130*c5fb1c25SMasahiro Yamada return 0; 131*c5fb1c25SMasahiro Yamada } 132*c5fb1c25SMasahiro Yamada 133b9a66b63SMasahiro Yamada static const struct dm_gpio_ops uniphier_gpio_ops = { 134b9a66b63SMasahiro Yamada .direction_input = uniphier_gpio_direction_input, 135b9a66b63SMasahiro Yamada .direction_output = uniphier_gpio_direction_output, 136b9a66b63SMasahiro Yamada .get_value = uniphier_gpio_get_value, 137b9a66b63SMasahiro Yamada .set_value = uniphier_gpio_set_value, 138b9a66b63SMasahiro Yamada .get_function = uniphier_gpio_get_function, 139b9a66b63SMasahiro Yamada }; 140b9a66b63SMasahiro Yamada 141b9a66b63SMasahiro Yamada static int uniphier_gpio_probe(struct udevice *dev) 142b9a66b63SMasahiro Yamada { 143b9a66b63SMasahiro Yamada struct uniphier_gpio_priv *priv = dev_get_priv(dev); 144b9a66b63SMasahiro Yamada struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 145b9a66b63SMasahiro Yamada fdt_addr_t addr; 146b9a66b63SMasahiro Yamada 147a821c4afSSimon Glass addr = devfdt_get_addr(dev); 148b9a66b63SMasahiro Yamada if (addr == FDT_ADDR_T_NONE) 149b9a66b63SMasahiro Yamada return -EINVAL; 150b9a66b63SMasahiro Yamada 151*c5fb1c25SMasahiro Yamada priv->regs = devm_ioremap(dev, addr, SZ_512); 152*c5fb1c25SMasahiro Yamada if (!priv->regs) 153b9a66b63SMasahiro Yamada return -ENOMEM; 154b9a66b63SMasahiro Yamada 155*c5fb1c25SMasahiro Yamada uc_priv->gpio_count = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), 156*c5fb1c25SMasahiro Yamada "ngpios", 0); 157b9a66b63SMasahiro Yamada 158b9a66b63SMasahiro Yamada return 0; 159b9a66b63SMasahiro Yamada } 160b9a66b63SMasahiro Yamada 161b9a66b63SMasahiro Yamada static const struct udevice_id uniphier_gpio_match[] = { 162b9a66b63SMasahiro Yamada { .compatible = "socionext,uniphier-gpio" }, 163b9a66b63SMasahiro Yamada { /* sentinel */ } 164b9a66b63SMasahiro Yamada }; 165b9a66b63SMasahiro Yamada 166b9a66b63SMasahiro Yamada U_BOOT_DRIVER(uniphier_gpio) = { 167*c5fb1c25SMasahiro Yamada .name = "uniphier-gpio", 168b9a66b63SMasahiro Yamada .id = UCLASS_GPIO, 169b9a66b63SMasahiro Yamada .of_match = uniphier_gpio_match, 170b9a66b63SMasahiro Yamada .probe = uniphier_gpio_probe, 171b9a66b63SMasahiro Yamada .priv_auto_alloc_size = sizeof(struct uniphier_gpio_priv), 172b9a66b63SMasahiro Yamada .ops = &uniphier_gpio_ops, 173b9a66b63SMasahiro Yamada }; 174