1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright 2016 Freescale Semiconductor, Inc. 4 * 5 * RGPIO2P driver for the Freescale i.MX7ULP. 6 */ 7 8 #include <common.h> 9 #include <dm.h> 10 #include <errno.h> 11 #include <fdtdec.h> 12 #include <asm/gpio.h> 13 #include <asm/io.h> 14 #include <malloc.h> 15 16 enum imx_rgpio2p_direction { 17 IMX_RGPIO2P_DIRECTION_IN, 18 IMX_RGPIO2P_DIRECTION_OUT, 19 }; 20 21 #define GPIO_PER_BANK 32 22 23 struct imx_rgpio2p_data { 24 struct gpio_regs *regs; 25 }; 26 27 struct imx_rgpio2p_plat { 28 int bank_index; 29 struct gpio_regs *regs; 30 }; 31 32 static int imx_rgpio2p_is_output(struct gpio_regs *regs, int offset) 33 { 34 u32 val; 35 36 val = readl(®s->gpio_pddr); 37 38 return val & (1 << offset) ? 1 : 0; 39 } 40 41 static void imx_rgpio2p_bank_direction(struct gpio_regs *regs, int offset, 42 enum imx_rgpio2p_direction direction) 43 { 44 u32 l; 45 46 l = readl(®s->gpio_pddr); 47 48 switch (direction) { 49 case IMX_RGPIO2P_DIRECTION_OUT: 50 l |= 1 << offset; 51 break; 52 case IMX_RGPIO2P_DIRECTION_IN: 53 l &= ~(1 << offset); 54 } 55 writel(l, ®s->gpio_pddr); 56 } 57 58 static void imx_rgpio2p_bank_set_value(struct gpio_regs *regs, int offset, 59 int value) 60 { 61 if (value) 62 writel((1 << offset), ®s->gpio_psor); 63 else 64 writel((1 << offset), ®s->gpio_pcor); 65 } 66 67 static int imx_rgpio2p_bank_get_value(struct gpio_regs *regs, int offset) 68 { 69 return (readl(®s->gpio_pdir) >> offset) & 0x01; 70 } 71 72 static int imx_rgpio2p_direction_input(struct udevice *dev, unsigned offset) 73 { 74 struct imx_rgpio2p_data *bank = dev_get_priv(dev); 75 76 /* Configure GPIO direction as input. */ 77 imx_rgpio2p_bank_direction(bank->regs, offset, IMX_RGPIO2P_DIRECTION_IN); 78 79 return 0; 80 } 81 82 static int imx_rgpio2p_direction_output(struct udevice *dev, unsigned offset, 83 int value) 84 { 85 struct imx_rgpio2p_data *bank = dev_get_priv(dev); 86 87 /* Configure GPIO output value. */ 88 imx_rgpio2p_bank_set_value(bank->regs, offset, value); 89 90 /* Configure GPIO direction as output. */ 91 imx_rgpio2p_bank_direction(bank->regs, offset, IMX_RGPIO2P_DIRECTION_OUT); 92 93 return 0; 94 } 95 96 static int imx_rgpio2p_get_value(struct udevice *dev, unsigned offset) 97 { 98 struct imx_rgpio2p_data *bank = dev_get_priv(dev); 99 100 return imx_rgpio2p_bank_get_value(bank->regs, offset); 101 } 102 103 static int imx_rgpio2p_set_value(struct udevice *dev, unsigned offset, 104 int value) 105 { 106 struct imx_rgpio2p_data *bank = dev_get_priv(dev); 107 108 imx_rgpio2p_bank_set_value(bank->regs, offset, value); 109 110 return 0; 111 } 112 113 static int imx_rgpio2p_get_function(struct udevice *dev, unsigned offset) 114 { 115 struct imx_rgpio2p_data *bank = dev_get_priv(dev); 116 117 /* GPIOF_FUNC is not implemented yet */ 118 if (imx_rgpio2p_is_output(bank->regs, offset)) 119 return GPIOF_OUTPUT; 120 else 121 return GPIOF_INPUT; 122 } 123 124 static const struct dm_gpio_ops imx_rgpio2p_ops = { 125 .direction_input = imx_rgpio2p_direction_input, 126 .direction_output = imx_rgpio2p_direction_output, 127 .get_value = imx_rgpio2p_get_value, 128 .set_value = imx_rgpio2p_set_value, 129 .get_function = imx_rgpio2p_get_function, 130 }; 131 132 static int imx_rgpio2p_probe(struct udevice *dev) 133 { 134 struct imx_rgpio2p_data *bank = dev_get_priv(dev); 135 struct imx_rgpio2p_plat *plat = dev_get_platdata(dev); 136 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 137 int banknum; 138 char name[18], *str; 139 140 banknum = plat->bank_index; 141 sprintf(name, "GPIO%d_", banknum + 1); 142 str = strdup(name); 143 if (!str) 144 return -ENOMEM; 145 uc_priv->bank_name = str; 146 uc_priv->gpio_count = GPIO_PER_BANK; 147 bank->regs = plat->regs; 148 149 return 0; 150 } 151 152 static int imx_rgpio2p_bind(struct udevice *dev) 153 { 154 struct imx_rgpio2p_plat *plat = dev->platdata; 155 fdt_addr_t addr; 156 157 /* 158 * If platdata already exsits, directly return. 159 * Actually only when DT is not supported, platdata 160 * is statically initialized in U_BOOT_DEVICES.Here 161 * will return. 162 */ 163 if (plat) 164 return 0; 165 166 addr = devfdt_get_addr_index(dev, 1); 167 if (addr == FDT_ADDR_T_NONE) 168 return -EINVAL; 169 170 /* 171 * TODO: 172 * When every board is converted to driver model and DT is supported, 173 * this can be done by auto-alloc feature, but not using calloc 174 * to alloc memory for platdata. 175 * 176 * For example imx_rgpio2p_plat uses platform data rather than device 177 * tree. 178 * 179 * NOTE: DO NOT COPY this code if you are using device tree. 180 */ 181 plat = calloc(1, sizeof(*plat)); 182 if (!plat) 183 return -ENOMEM; 184 185 plat->regs = (struct gpio_regs *)addr; 186 plat->bank_index = dev->req_seq; 187 dev->platdata = plat; 188 189 return 0; 190 } 191 192 193 static const struct udevice_id imx_rgpio2p_ids[] = { 194 { .compatible = "fsl,imx7ulp-gpio" }, 195 { } 196 }; 197 198 U_BOOT_DRIVER(imx_rgpio2p) = { 199 .name = "imx_rgpio2p", 200 .id = UCLASS_GPIO, 201 .ops = &imx_rgpio2p_ops, 202 .probe = imx_rgpio2p_probe, 203 .priv_auto_alloc_size = sizeof(struct imx_rgpio2p_plat), 204 .of_match = imx_rgpio2p_ids, 205 .bind = imx_rgpio2p_bind, 206 }; 207 208 #if !CONFIG_IS_ENABLED(OF_CONTROL) 209 static const struct imx_rgpio2p_plat imx_plat[] = { 210 { 0, (struct gpio_regs *)RGPIO2P_GPIO1_BASE_ADDR }, 211 { 1, (struct gpio_regs *)RGPIO2P_GPIO2_BASE_ADDR }, 212 { 2, (struct gpio_regs *)RGPIO2P_GPIO3_BASE_ADDR }, 213 { 3, (struct gpio_regs *)RGPIO2P_GPIO4_BASE_ADDR }, 214 { 4, (struct gpio_regs *)RGPIO2P_GPIO5_BASE_ADDR }, 215 { 5, (struct gpio_regs *)RGPIO2P_GPIO6_BASE_ADDR }, 216 }; 217 218 U_BOOT_DEVICES(imx_rgpio2ps) = { 219 { "imx_rgpio2p", &imx_plat[0] }, 220 { "imx_rgpio2p", &imx_plat[1] }, 221 { "imx_rgpio2p", &imx_plat[2] }, 222 { "imx_rgpio2p", &imx_plat[3] }, 223 { "imx_rgpio2p", &imx_plat[4] }, 224 { "imx_rgpio2p", &imx_plat[5] }, 225 }; 226 #endif 227