1 /* 2 * (C) Copyright 2015 Google, Inc 3 * 4 * (C) Copyright 2008-2014 Rockchip Electronics 5 * Peter, Software Engineering, <superpeter.cai@gmail.com>. 6 * 7 * SPDX-License-Identifier: GPL-2.0+ 8 */ 9 10 #include <common.h> 11 #include <clk.h> 12 #include <dm.h> 13 #include <syscon.h> 14 #include <asm/errno.h> 15 #include <asm/gpio.h> 16 #include <asm/io.h> 17 #include <asm/arch/clock.h> 18 #include <dm/pinctrl.h> 19 #include <dt-bindings/clock/rk3288-cru.h> 20 21 enum { 22 ROCKCHIP_GPIOS_PER_BANK = 32, 23 }; 24 25 #define OFFSET_TO_BIT(bit) (1UL << (bit)) 26 27 struct rockchip_gpio_priv { 28 struct rockchip_gpio_regs *regs; 29 struct udevice *pinctrl; 30 int bank; 31 char name[2]; 32 }; 33 34 static int rockchip_gpio_direction_input(struct udevice *dev, unsigned offset) 35 { 36 struct rockchip_gpio_priv *priv = dev_get_priv(dev); 37 struct rockchip_gpio_regs *regs = priv->regs; 38 39 clrbits_le32(®s->swport_ddr, OFFSET_TO_BIT(offset)); 40 41 return 0; 42 } 43 44 static int rockchip_gpio_direction_output(struct udevice *dev, unsigned offset, 45 int value) 46 { 47 struct rockchip_gpio_priv *priv = dev_get_priv(dev); 48 struct rockchip_gpio_regs *regs = priv->regs; 49 int mask = OFFSET_TO_BIT(offset); 50 51 clrsetbits_le32(®s->swport_dr, mask, value ? mask : 0); 52 setbits_le32(®s->swport_ddr, mask); 53 54 return 0; 55 } 56 57 static int rockchip_gpio_get_value(struct udevice *dev, unsigned offset) 58 { 59 struct rockchip_gpio_priv *priv = dev_get_priv(dev); 60 struct rockchip_gpio_regs *regs = priv->regs; 61 62 return readl(®s->ext_port) & OFFSET_TO_BIT(offset) ? 1 : 0; 63 } 64 65 static int rockchip_gpio_set_value(struct udevice *dev, unsigned offset, 66 int value) 67 { 68 struct rockchip_gpio_priv *priv = dev_get_priv(dev); 69 struct rockchip_gpio_regs *regs = priv->regs; 70 int mask = OFFSET_TO_BIT(offset); 71 72 clrsetbits_le32(®s->swport_dr, mask, value ? mask : 0); 73 74 return 0; 75 } 76 77 static int rockchip_gpio_get_function(struct udevice *dev, unsigned offset) 78 { 79 #ifdef CONFIG_SPL_BUILD 80 return -ENODATA; 81 #else 82 struct rockchip_gpio_priv *priv = dev_get_priv(dev); 83 struct rockchip_gpio_regs *regs = priv->regs; 84 bool is_output; 85 int ret; 86 87 ret = pinctrl_get_gpio_mux(priv->pinctrl, priv->bank, offset); 88 if (ret) 89 return ret; 90 91 /* If it's not 0, then it is not a GPIO */ 92 if (ret) 93 return GPIOF_FUNC; 94 is_output = readl(®s->swport_ddr) & OFFSET_TO_BIT(offset); 95 96 return is_output ? GPIOF_OUTPUT : GPIOF_INPUT; 97 #endif 98 } 99 100 static int rockchip_gpio_probe(struct udevice *dev) 101 { 102 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 103 struct rockchip_gpio_priv *priv = dev_get_priv(dev); 104 char *end; 105 int ret; 106 107 /* This only supports RK3288 at present */ 108 priv->regs = (struct rockchip_gpio_regs *)dev_get_addr(dev); 109 ret = uclass_first_device_err(UCLASS_PINCTRL, &priv->pinctrl); 110 if (ret) 111 return ret; 112 113 uc_priv->gpio_count = ROCKCHIP_GPIOS_PER_BANK; 114 end = strrchr(dev->name, '@'); 115 priv->bank = trailing_strtoln(dev->name, end); 116 priv->name[0] = 'A' + priv->bank; 117 uc_priv->bank_name = priv->name; 118 119 return 0; 120 } 121 122 static const struct dm_gpio_ops gpio_rockchip_ops = { 123 .direction_input = rockchip_gpio_direction_input, 124 .direction_output = rockchip_gpio_direction_output, 125 .get_value = rockchip_gpio_get_value, 126 .set_value = rockchip_gpio_set_value, 127 .get_function = rockchip_gpio_get_function, 128 }; 129 130 static const struct udevice_id rockchip_gpio_ids[] = { 131 { .compatible = "rockchip,gpio-bank" }, 132 { } 133 }; 134 135 U_BOOT_DRIVER(gpio_rockchip) = { 136 .name = "gpio_rockchip", 137 .id = UCLASS_GPIO, 138 .of_match = rockchip_gpio_ids, 139 .ops = &gpio_rockchip_ops, 140 .priv_auto_alloc_size = sizeof(struct rockchip_gpio_priv), 141 .probe = rockchip_gpio_probe, 142 }; 143