11f8f7730SSimon Glass /* 21f8f7730SSimon Glass * (C) Copyright 2015 Google, Inc 31f8f7730SSimon Glass * 4d1aef94bSJianqun Xu * (C) Copyright 2008-2020 Rockchip Electronics 51f8f7730SSimon Glass * Peter, Software Engineering, <superpeter.cai@gmail.com>. 6d1aef94bSJianqun Xu * Jianqun Xu, Software Engineering, <jay.xu@rock-chips.com>. 71f8f7730SSimon Glass * 81f8f7730SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 91f8f7730SSimon Glass */ 101f8f7730SSimon Glass 111f8f7730SSimon Glass #include <common.h> 121f8f7730SSimon Glass #include <dm.h> 1348647828SSimon Glass #include <syscon.h> 141221ce45SMasahiro Yamada #include <linux/errno.h> 151f8f7730SSimon Glass #include <asm/gpio.h> 161f8f7730SSimon Glass #include <asm/io.h> 1748647828SSimon Glass #include <asm/arch/clock.h> 1848647828SSimon Glass #include <dm/pinctrl.h> 1948647828SSimon Glass #include <dt-bindings/clock/rk3288-cru.h> 201f8f7730SSimon Glass 211f8f7730SSimon Glass enum { 221f8f7730SSimon Glass ROCKCHIP_GPIOS_PER_BANK = 32, 231f8f7730SSimon Glass }; 241f8f7730SSimon Glass 251f8f7730SSimon Glass #define OFFSET_TO_BIT(bit) (1UL << (bit)) 261f8f7730SSimon Glass 27d1aef94bSJianqun Xu #ifdef CONFIG_ROCKCHIP_GPIO_V2 28d1aef94bSJianqun Xu #define REG_L(R) (R##_l) 29d1aef94bSJianqun Xu #define REG_H(R) (R##_h) 30d1aef94bSJianqun Xu #define READ_REG(REG) ((readl(REG_L(REG)) & 0xFFFF) | \ 31d1aef94bSJianqun Xu ((readl(REG_H(REG)) & 0xFFFF) << 16)) 32d1aef94bSJianqun Xu #define WRITE_REG(REG, VAL) \ 33d1aef94bSJianqun Xu {\ 34d1aef94bSJianqun Xu writel(((VAL) & 0xFFFF) | 0xFFFF0000, REG_L(REG)); \ 35d1aef94bSJianqun Xu writel((((VAL) & 0xFFFF0000) >> 16) | 0xFFFF0000, REG_H(REG));\ 36d1aef94bSJianqun Xu } 37d1aef94bSJianqun Xu #define CLRBITS_LE32(REG, MASK) WRITE_REG(REG, READ_REG(REG) & ~(MASK)) 38d1aef94bSJianqun Xu #define SETBITS_LE32(REG, MASK) WRITE_REG(REG, READ_REG(REG) | (MASK)) 39d1aef94bSJianqun Xu #define CLRSETBITS_LE32(REG, MASK, VAL) WRITE_REG(REG, \ 40d1aef94bSJianqun Xu (READ_REG(REG) & ~(MASK)) | (VAL)) 41d1aef94bSJianqun Xu 42d1aef94bSJianqun Xu #else 43d1aef94bSJianqun Xu #define READ_REG(REG) readl(REG) 44d1aef94bSJianqun Xu #define WRITE_REG(REG, VAL) writel(VAL, REG) 45d1aef94bSJianqun Xu #define CLRBITS_LE32(REG, MASK) clrbits_le32(REG, MASK) 46d1aef94bSJianqun Xu #define SETBITS_LE32(REG, MASK) setbits_le32(REG, MASK) 47d1aef94bSJianqun Xu #define CLRSETBITS_LE32(REG, MASK, VAL) clrsetbits_le32(REG, MASK, VAL) 48d1aef94bSJianqun Xu #endif 49d1aef94bSJianqun Xu 50d1aef94bSJianqun Xu 511f8f7730SSimon Glass struct rockchip_gpio_priv { 521f8f7730SSimon Glass struct rockchip_gpio_regs *regs; 5348647828SSimon Glass struct udevice *pinctrl; 5448647828SSimon Glass int bank; 551f8f7730SSimon Glass char name[2]; 561f8f7730SSimon Glass }; 571f8f7730SSimon Glass 581f8f7730SSimon Glass static int rockchip_gpio_direction_input(struct udevice *dev, unsigned offset) 591f8f7730SSimon Glass { 601f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev); 611f8f7730SSimon Glass struct rockchip_gpio_regs *regs = priv->regs; 621f8f7730SSimon Glass 63d1aef94bSJianqun Xu CLRBITS_LE32(®s->swport_ddr, OFFSET_TO_BIT(offset)); 641f8f7730SSimon Glass 651f8f7730SSimon Glass return 0; 661f8f7730SSimon Glass } 671f8f7730SSimon Glass 681f8f7730SSimon Glass static int rockchip_gpio_direction_output(struct udevice *dev, unsigned offset, 691f8f7730SSimon Glass int value) 701f8f7730SSimon Glass { 711f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev); 721f8f7730SSimon Glass struct rockchip_gpio_regs *regs = priv->regs; 731f8f7730SSimon Glass int mask = OFFSET_TO_BIT(offset); 741f8f7730SSimon Glass 75d1aef94bSJianqun Xu CLRSETBITS_LE32(®s->swport_dr, mask, value ? mask : 0); 76d1aef94bSJianqun Xu SETBITS_LE32(®s->swport_ddr, mask); 771f8f7730SSimon Glass 781f8f7730SSimon Glass return 0; 791f8f7730SSimon Glass } 801f8f7730SSimon Glass 811f8f7730SSimon Glass static int rockchip_gpio_get_value(struct udevice *dev, unsigned offset) 821f8f7730SSimon Glass { 831f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev); 841f8f7730SSimon Glass struct rockchip_gpio_regs *regs = priv->regs; 851f8f7730SSimon Glass 867d0c2c3fSSimon Glass return readl(®s->ext_port) & OFFSET_TO_BIT(offset) ? 1 : 0; 871f8f7730SSimon Glass } 881f8f7730SSimon Glass 891f8f7730SSimon Glass static int rockchip_gpio_set_value(struct udevice *dev, unsigned offset, 901f8f7730SSimon Glass int value) 911f8f7730SSimon Glass { 921f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev); 931f8f7730SSimon Glass struct rockchip_gpio_regs *regs = priv->regs; 941f8f7730SSimon Glass int mask = OFFSET_TO_BIT(offset); 951f8f7730SSimon Glass 96d1aef94bSJianqun Xu CLRSETBITS_LE32(®s->swport_dr, mask, value ? mask : 0); 971f8f7730SSimon Glass 981f8f7730SSimon Glass return 0; 991f8f7730SSimon Glass } 1001f8f7730SSimon Glass 1011f8f7730SSimon Glass static int rockchip_gpio_get_function(struct udevice *dev, unsigned offset) 1021f8f7730SSimon Glass { 10348647828SSimon Glass #ifdef CONFIG_SPL_BUILD 10448647828SSimon Glass return -ENODATA; 10548647828SSimon Glass #else 10648647828SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev); 10748647828SSimon Glass struct rockchip_gpio_regs *regs = priv->regs; 10848647828SSimon Glass bool is_output; 10948647828SSimon Glass int ret; 11048647828SSimon Glass 11148647828SSimon Glass ret = pinctrl_get_gpio_mux(priv->pinctrl, priv->bank, offset); 11248647828SSimon Glass if (ret) 11348647828SSimon Glass return ret; 11448647828SSimon Glass 11548647828SSimon Glass /* If it's not 0, then it is not a GPIO */ 11648647828SSimon Glass if (ret) 11748647828SSimon Glass return GPIOF_FUNC; 118d1aef94bSJianqun Xu 119d1aef94bSJianqun Xu is_output = READ_REG(®s->swport_ddr) & OFFSET_TO_BIT(offset); 12048647828SSimon Glass 12148647828SSimon Glass return is_output ? GPIOF_OUTPUT : GPIOF_INPUT; 12248647828SSimon Glass #endif 1231f8f7730SSimon Glass } 1241f8f7730SSimon Glass 1251f8f7730SSimon Glass static int rockchip_gpio_probe(struct udevice *dev) 1261f8f7730SSimon Glass { 1271f8f7730SSimon Glass struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 1281f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev); 1291f8f7730SSimon Glass char *end; 1307d13e745SJianqun Xu int pins_num; 13148647828SSimon Glass int ret; 1321f8f7730SSimon Glass 13355efd69cSPhilipp Tomsich priv->regs = dev_read_addr_ptr(dev); 1343f603cbbSSimon Glass ret = uclass_first_device_err(UCLASS_PINCTRL, &priv->pinctrl); 13548647828SSimon Glass if (ret) 13648647828SSimon Glass return ret; 13748647828SSimon Glass 1381f8f7730SSimon Glass uc_priv->gpio_count = ROCKCHIP_GPIOS_PER_BANK; 1391f8f7730SSimon Glass end = strrchr(dev->name, '@'); 14048647828SSimon Glass priv->bank = trailing_strtoln(dev->name, end); 14148647828SSimon Glass priv->name[0] = 'A' + priv->bank; 1421f8f7730SSimon Glass uc_priv->bank_name = priv->name; 1431f8f7730SSimon Glass 1447d13e745SJianqun Xu pins_num = pinctrl_get_pins_count(priv->pinctrl); 145*9f32e0d2SJianqun Xu if (pins_num <= 0) { 146*9f32e0d2SJianqun Xu printf("%s: fail to get pins from pinctrl\n", __func__); 147*9f32e0d2SJianqun Xu } else if ((priv->bank + 1) * ROCKCHIP_GPIOS_PER_BANK >= pins_num) { 1487d13e745SJianqun Xu uc_priv->gpio_count = pins_num - priv->bank * ROCKCHIP_GPIOS_PER_BANK; 149*9f32e0d2SJianqun Xu } 1507d13e745SJianqun Xu 1511f8f7730SSimon Glass return 0; 1521f8f7730SSimon Glass } 1531f8f7730SSimon Glass 1541f8f7730SSimon Glass static const struct dm_gpio_ops gpio_rockchip_ops = { 1551f8f7730SSimon Glass .direction_input = rockchip_gpio_direction_input, 1561f8f7730SSimon Glass .direction_output = rockchip_gpio_direction_output, 1571f8f7730SSimon Glass .get_value = rockchip_gpio_get_value, 1581f8f7730SSimon Glass .set_value = rockchip_gpio_set_value, 1591f8f7730SSimon Glass .get_function = rockchip_gpio_get_function, 1601f8f7730SSimon Glass }; 1611f8f7730SSimon Glass 1621f8f7730SSimon Glass static const struct udevice_id rockchip_gpio_ids[] = { 1631f8f7730SSimon Glass { .compatible = "rockchip,gpio-bank" }, 1641f8f7730SSimon Glass { } 1651f8f7730SSimon Glass }; 1661f8f7730SSimon Glass 1671f8f7730SSimon Glass U_BOOT_DRIVER(gpio_rockchip) = { 1681f8f7730SSimon Glass .name = "gpio_rockchip", 1691f8f7730SSimon Glass .id = UCLASS_GPIO, 1701f8f7730SSimon Glass .of_match = rockchip_gpio_ids, 1711f8f7730SSimon Glass .ops = &gpio_rockchip_ops, 1721f8f7730SSimon Glass .priv_auto_alloc_size = sizeof(struct rockchip_gpio_priv), 1731f8f7730SSimon Glass .probe = rockchip_gpio_probe, 1741f8f7730SSimon Glass }; 175