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> 11*48647828SSimon Glass #include <clk.h> 121f8f7730SSimon Glass #include <dm.h> 13*48647828SSimon Glass #include <syscon.h> 141f8f7730SSimon Glass #include <asm/errno.h> 151f8f7730SSimon Glass #include <asm/gpio.h> 161f8f7730SSimon Glass #include <asm/io.h> 17*48647828SSimon Glass #include <asm/arch/clock.h> 18*48647828SSimon Glass #include <dm/pinctrl.h> 191f8f7730SSimon Glass #include <dt-bindings/gpio/gpio.h> 20*48647828SSimon Glass #include <dt-bindings/clock/rk3288-cru.h> 211f8f7730SSimon Glass 221f8f7730SSimon Glass enum { 231f8f7730SSimon Glass ROCKCHIP_GPIOS_PER_BANK = 32, 241f8f7730SSimon Glass }; 251f8f7730SSimon Glass 261f8f7730SSimon Glass #define OFFSET_TO_BIT(bit) (1UL << (bit)) 271f8f7730SSimon Glass 281f8f7730SSimon Glass struct rockchip_gpio_priv { 291f8f7730SSimon Glass struct rockchip_gpio_regs *regs; 30*48647828SSimon Glass struct udevice *pinctrl; 31*48647828SSimon Glass int bank; 321f8f7730SSimon Glass char name[2]; 331f8f7730SSimon Glass }; 341f8f7730SSimon Glass 351f8f7730SSimon Glass static int rockchip_gpio_direction_input(struct udevice *dev, unsigned offset) 361f8f7730SSimon Glass { 371f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev); 381f8f7730SSimon Glass struct rockchip_gpio_regs *regs = priv->regs; 391f8f7730SSimon Glass 401f8f7730SSimon Glass clrbits_le32(®s->swport_ddr, OFFSET_TO_BIT(offset)); 411f8f7730SSimon Glass 421f8f7730SSimon Glass return 0; 431f8f7730SSimon Glass } 441f8f7730SSimon Glass 451f8f7730SSimon Glass static int rockchip_gpio_direction_output(struct udevice *dev, unsigned offset, 461f8f7730SSimon Glass int value) 471f8f7730SSimon Glass { 481f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev); 491f8f7730SSimon Glass struct rockchip_gpio_regs *regs = priv->regs; 501f8f7730SSimon Glass int mask = OFFSET_TO_BIT(offset); 511f8f7730SSimon Glass 521f8f7730SSimon Glass clrsetbits_le32(®s->swport_dr, mask, value ? mask : 0); 531f8f7730SSimon Glass setbits_le32(®s->swport_ddr, mask); 541f8f7730SSimon Glass 551f8f7730SSimon Glass return 0; 561f8f7730SSimon Glass } 571f8f7730SSimon Glass 581f8f7730SSimon Glass static int rockchip_gpio_get_value(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 637d0c2c3fSSimon Glass return readl(®s->ext_port) & OFFSET_TO_BIT(offset) ? 1 : 0; 641f8f7730SSimon Glass } 651f8f7730SSimon Glass 661f8f7730SSimon Glass static int rockchip_gpio_set_value(struct udevice *dev, unsigned offset, 671f8f7730SSimon Glass int value) 681f8f7730SSimon Glass { 691f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev); 701f8f7730SSimon Glass struct rockchip_gpio_regs *regs = priv->regs; 711f8f7730SSimon Glass int mask = OFFSET_TO_BIT(offset); 721f8f7730SSimon Glass 731f8f7730SSimon Glass clrsetbits_le32(®s->swport_dr, mask, value ? mask : 0); 741f8f7730SSimon Glass 751f8f7730SSimon Glass return 0; 761f8f7730SSimon Glass } 771f8f7730SSimon Glass 781f8f7730SSimon Glass static int rockchip_gpio_get_function(struct udevice *dev, unsigned offset) 791f8f7730SSimon Glass { 80*48647828SSimon Glass #ifdef CONFIG_SPL_BUILD 81*48647828SSimon Glass return -ENODATA; 82*48647828SSimon Glass #else 83*48647828SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev); 84*48647828SSimon Glass struct rockchip_gpio_regs *regs = priv->regs; 85*48647828SSimon Glass bool is_output; 86*48647828SSimon Glass int ret; 87*48647828SSimon Glass 88*48647828SSimon Glass ret = pinctrl_get_gpio_mux(priv->pinctrl, priv->bank, offset); 89*48647828SSimon Glass if (ret) 90*48647828SSimon Glass return ret; 91*48647828SSimon Glass 92*48647828SSimon Glass /* If it's not 0, then it is not a GPIO */ 93*48647828SSimon Glass if (ret) 94*48647828SSimon Glass return GPIOF_FUNC; 95*48647828SSimon Glass is_output = readl(®s->swport_ddr) & OFFSET_TO_BIT(offset); 96*48647828SSimon Glass 97*48647828SSimon Glass return is_output ? GPIOF_OUTPUT : GPIOF_INPUT; 98*48647828SSimon Glass #endif 991f8f7730SSimon Glass } 1001f8f7730SSimon Glass 1011f8f7730SSimon Glass static int rockchip_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, 1021f8f7730SSimon Glass struct fdtdec_phandle_args *args) 1031f8f7730SSimon Glass { 1041f8f7730SSimon Glass desc->offset = args->args[0]; 1051f8f7730SSimon Glass desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0; 1061f8f7730SSimon Glass 1071f8f7730SSimon Glass return 0; 1081f8f7730SSimon Glass } 1091f8f7730SSimon Glass 1101f8f7730SSimon Glass static int rockchip_gpio_probe(struct udevice *dev) 1111f8f7730SSimon Glass { 1121f8f7730SSimon Glass struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 1131f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev); 1141f8f7730SSimon Glass char *end; 115*48647828SSimon Glass int ret; 1161f8f7730SSimon Glass 117*48647828SSimon Glass /* This only supports RK3288 at present */ 1181f8f7730SSimon Glass priv->regs = (struct rockchip_gpio_regs *)dev_get_addr(dev); 119*48647828SSimon Glass ret = uclass_first_device(UCLASS_PINCTRL, &priv->pinctrl); 120*48647828SSimon Glass if (ret) 121*48647828SSimon Glass return ret; 122*48647828SSimon Glass if (!priv->pinctrl) 123*48647828SSimon Glass return -ENODEV; 124*48647828SSimon Glass 1251f8f7730SSimon Glass uc_priv->gpio_count = ROCKCHIP_GPIOS_PER_BANK; 1261f8f7730SSimon Glass end = strrchr(dev->name, '@'); 127*48647828SSimon Glass priv->bank = trailing_strtoln(dev->name, end); 128*48647828SSimon Glass priv->name[0] = 'A' + priv->bank; 1291f8f7730SSimon Glass uc_priv->bank_name = priv->name; 1301f8f7730SSimon Glass 1311f8f7730SSimon Glass return 0; 1321f8f7730SSimon Glass } 1331f8f7730SSimon Glass 1341f8f7730SSimon Glass static const struct dm_gpio_ops gpio_rockchip_ops = { 1351f8f7730SSimon Glass .direction_input = rockchip_gpio_direction_input, 1361f8f7730SSimon Glass .direction_output = rockchip_gpio_direction_output, 1371f8f7730SSimon Glass .get_value = rockchip_gpio_get_value, 1381f8f7730SSimon Glass .set_value = rockchip_gpio_set_value, 1391f8f7730SSimon Glass .get_function = rockchip_gpio_get_function, 1401f8f7730SSimon Glass .xlate = rockchip_gpio_xlate, 1411f8f7730SSimon Glass }; 1421f8f7730SSimon Glass 1431f8f7730SSimon Glass static const struct udevice_id rockchip_gpio_ids[] = { 1441f8f7730SSimon Glass { .compatible = "rockchip,gpio-bank" }, 1451f8f7730SSimon Glass { } 1461f8f7730SSimon Glass }; 1471f8f7730SSimon Glass 1481f8f7730SSimon Glass U_BOOT_DRIVER(gpio_rockchip) = { 1491f8f7730SSimon Glass .name = "gpio_rockchip", 1501f8f7730SSimon Glass .id = UCLASS_GPIO, 1511f8f7730SSimon Glass .of_match = rockchip_gpio_ids, 1521f8f7730SSimon Glass .ops = &gpio_rockchip_ops, 1531f8f7730SSimon Glass .priv_auto_alloc_size = sizeof(struct rockchip_gpio_priv), 1541f8f7730SSimon Glass .probe = rockchip_gpio_probe, 1551f8f7730SSimon Glass }; 156