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