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