11f8f7730SSimon Glass /* 21f8f7730SSimon Glass * (C) Copyright 2015 Google, Inc 31f8f7730SSimon Glass * 41f8f7730SSimon Glass * (C) Copyright 2008-2014 Rockchip Electronics 51f8f7730SSimon Glass * Peter, Software Engineering, <superpeter.cai@gmail.com>. 61f8f7730SSimon Glass * 71f8f7730SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 81f8f7730SSimon Glass */ 91f8f7730SSimon Glass 101f8f7730SSimon Glass #include <common.h> 111f8f7730SSimon Glass #include <dm.h> 1248647828SSimon Glass #include <syscon.h> 13*1221ce45SMasahiro Yamada #include <linux/errno.h> 141f8f7730SSimon Glass #include <asm/gpio.h> 151f8f7730SSimon Glass #include <asm/io.h> 1648647828SSimon Glass #include <asm/arch/clock.h> 1748647828SSimon Glass #include <dm/pinctrl.h> 1848647828SSimon Glass #include <dt-bindings/clock/rk3288-cru.h> 191f8f7730SSimon Glass 201f8f7730SSimon Glass enum { 211f8f7730SSimon Glass ROCKCHIP_GPIOS_PER_BANK = 32, 221f8f7730SSimon Glass }; 231f8f7730SSimon Glass 241f8f7730SSimon Glass #define OFFSET_TO_BIT(bit) (1UL << (bit)) 251f8f7730SSimon Glass 261f8f7730SSimon Glass struct rockchip_gpio_priv { 271f8f7730SSimon Glass struct rockchip_gpio_regs *regs; 2848647828SSimon Glass struct udevice *pinctrl; 2948647828SSimon Glass int bank; 301f8f7730SSimon Glass char name[2]; 311f8f7730SSimon Glass }; 321f8f7730SSimon Glass 331f8f7730SSimon Glass static int rockchip_gpio_direction_input(struct udevice *dev, unsigned offset) 341f8f7730SSimon Glass { 351f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev); 361f8f7730SSimon Glass struct rockchip_gpio_regs *regs = priv->regs; 371f8f7730SSimon Glass 381f8f7730SSimon Glass clrbits_le32(®s->swport_ddr, OFFSET_TO_BIT(offset)); 391f8f7730SSimon Glass 401f8f7730SSimon Glass return 0; 411f8f7730SSimon Glass } 421f8f7730SSimon Glass 431f8f7730SSimon Glass static int rockchip_gpio_direction_output(struct udevice *dev, unsigned offset, 441f8f7730SSimon Glass int value) 451f8f7730SSimon Glass { 461f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev); 471f8f7730SSimon Glass struct rockchip_gpio_regs *regs = priv->regs; 481f8f7730SSimon Glass int mask = OFFSET_TO_BIT(offset); 491f8f7730SSimon Glass 501f8f7730SSimon Glass clrsetbits_le32(®s->swport_dr, mask, value ? mask : 0); 511f8f7730SSimon Glass setbits_le32(®s->swport_ddr, mask); 521f8f7730SSimon Glass 531f8f7730SSimon Glass return 0; 541f8f7730SSimon Glass } 551f8f7730SSimon Glass 561f8f7730SSimon Glass static int rockchip_gpio_get_value(struct udevice *dev, unsigned offset) 571f8f7730SSimon Glass { 581f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev); 591f8f7730SSimon Glass struct rockchip_gpio_regs *regs = priv->regs; 601f8f7730SSimon Glass 617d0c2c3fSSimon Glass return readl(®s->ext_port) & OFFSET_TO_BIT(offset) ? 1 : 0; 621f8f7730SSimon Glass } 631f8f7730SSimon Glass 641f8f7730SSimon Glass static int rockchip_gpio_set_value(struct udevice *dev, unsigned offset, 651f8f7730SSimon Glass int value) 661f8f7730SSimon Glass { 671f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev); 681f8f7730SSimon Glass struct rockchip_gpio_regs *regs = priv->regs; 691f8f7730SSimon Glass int mask = OFFSET_TO_BIT(offset); 701f8f7730SSimon Glass 711f8f7730SSimon Glass clrsetbits_le32(®s->swport_dr, mask, value ? mask : 0); 721f8f7730SSimon Glass 731f8f7730SSimon Glass return 0; 741f8f7730SSimon Glass } 751f8f7730SSimon Glass 761f8f7730SSimon Glass static int rockchip_gpio_get_function(struct udevice *dev, unsigned offset) 771f8f7730SSimon Glass { 7848647828SSimon Glass #ifdef CONFIG_SPL_BUILD 7948647828SSimon Glass return -ENODATA; 8048647828SSimon Glass #else 8148647828SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev); 8248647828SSimon Glass struct rockchip_gpio_regs *regs = priv->regs; 8348647828SSimon Glass bool is_output; 8448647828SSimon Glass int ret; 8548647828SSimon Glass 8648647828SSimon Glass ret = pinctrl_get_gpio_mux(priv->pinctrl, priv->bank, offset); 8748647828SSimon Glass if (ret) 8848647828SSimon Glass return ret; 8948647828SSimon Glass 9048647828SSimon Glass /* If it's not 0, then it is not a GPIO */ 9148647828SSimon Glass if (ret) 9248647828SSimon Glass return GPIOF_FUNC; 9348647828SSimon Glass is_output = readl(®s->swport_ddr) & OFFSET_TO_BIT(offset); 9448647828SSimon Glass 9548647828SSimon Glass return is_output ? GPIOF_OUTPUT : GPIOF_INPUT; 9648647828SSimon Glass #endif 971f8f7730SSimon Glass } 981f8f7730SSimon Glass 991f8f7730SSimon Glass static int rockchip_gpio_probe(struct udevice *dev) 1001f8f7730SSimon Glass { 1011f8f7730SSimon Glass struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 1021f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev); 1031f8f7730SSimon Glass char *end; 10448647828SSimon Glass int ret; 1051f8f7730SSimon Glass 10648647828SSimon Glass /* This only supports RK3288 at present */ 1071f8f7730SSimon Glass priv->regs = (struct rockchip_gpio_regs *)dev_get_addr(dev); 1083f603cbbSSimon Glass ret = uclass_first_device_err(UCLASS_PINCTRL, &priv->pinctrl); 10948647828SSimon Glass if (ret) 11048647828SSimon Glass return ret; 11148647828SSimon Glass 1121f8f7730SSimon Glass uc_priv->gpio_count = ROCKCHIP_GPIOS_PER_BANK; 1131f8f7730SSimon Glass end = strrchr(dev->name, '@'); 11448647828SSimon Glass priv->bank = trailing_strtoln(dev->name, end); 11548647828SSimon Glass priv->name[0] = 'A' + priv->bank; 1161f8f7730SSimon Glass uc_priv->bank_name = priv->name; 1171f8f7730SSimon Glass 1181f8f7730SSimon Glass return 0; 1191f8f7730SSimon Glass } 1201f8f7730SSimon Glass 1211f8f7730SSimon Glass static const struct dm_gpio_ops gpio_rockchip_ops = { 1221f8f7730SSimon Glass .direction_input = rockchip_gpio_direction_input, 1231f8f7730SSimon Glass .direction_output = rockchip_gpio_direction_output, 1241f8f7730SSimon Glass .get_value = rockchip_gpio_get_value, 1251f8f7730SSimon Glass .set_value = rockchip_gpio_set_value, 1261f8f7730SSimon Glass .get_function = rockchip_gpio_get_function, 1271f8f7730SSimon Glass }; 1281f8f7730SSimon Glass 1291f8f7730SSimon Glass static const struct udevice_id rockchip_gpio_ids[] = { 1301f8f7730SSimon Glass { .compatible = "rockchip,gpio-bank" }, 1311f8f7730SSimon Glass { } 1321f8f7730SSimon Glass }; 1331f8f7730SSimon Glass 1341f8f7730SSimon Glass U_BOOT_DRIVER(gpio_rockchip) = { 1351f8f7730SSimon Glass .name = "gpio_rockchip", 1361f8f7730SSimon Glass .id = UCLASS_GPIO, 1371f8f7730SSimon Glass .of_match = rockchip_gpio_ids, 1381f8f7730SSimon Glass .ops = &gpio_rockchip_ops, 1391f8f7730SSimon Glass .priv_auto_alloc_size = sizeof(struct rockchip_gpio_priv), 1401f8f7730SSimon Glass .probe = rockchip_gpio_probe, 1411f8f7730SSimon Glass }; 142