1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2009 4 * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de> 5 * 6 * Copyright (C) 2011 7 * Stefano Babic, DENX Software Engineering, <sbabic@denx.de> 8 */ 9 #include <common.h> 10 #include <errno.h> 11 #include <dm.h> 12 #include <malloc.h> 13 #include <asm/arch/imx-regs.h> 14 #include <asm/gpio.h> 15 #include <asm/io.h> 16 17 enum mxc_gpio_direction { 18 MXC_GPIO_DIRECTION_IN, 19 MXC_GPIO_DIRECTION_OUT, 20 }; 21 22 #define GPIO_PER_BANK 32 23 24 struct mxc_gpio_plat { 25 int bank_index; 26 struct gpio_regs *regs; 27 }; 28 29 struct mxc_bank_info { 30 struct gpio_regs *regs; 31 }; 32 33 #ifndef CONFIG_DM_GPIO 34 #define GPIO_TO_PORT(n) (n / 32) 35 36 /* GPIO port description */ 37 static unsigned long gpio_ports[] = { 38 [0] = GPIO1_BASE_ADDR, 39 [1] = GPIO2_BASE_ADDR, 40 [2] = GPIO3_BASE_ADDR, 41 #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \ 42 defined(CONFIG_MX53) || defined(CONFIG_MX6) || \ 43 defined(CONFIG_MX7) || defined(CONFIG_MX8M) || \ 44 defined(CONFIG_ARCH_IMX8) 45 [3] = GPIO4_BASE_ADDR, 46 #endif 47 #if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6) || \ 48 defined(CONFIG_MX7) || defined(CONFIG_MX8M) || \ 49 defined(CONFIG_ARCH_IMX8) 50 [4] = GPIO5_BASE_ADDR, 51 #if !(defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL) || defined(CONFIG_MX8M)) 52 [5] = GPIO6_BASE_ADDR, 53 #endif 54 #endif 55 #if defined(CONFIG_MX53) || defined(CONFIG_MX6) || defined(CONFIG_MX7) || \ 56 defined(CONFIG_ARCH_IMX8) 57 #if !(defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL)) 58 [6] = GPIO7_BASE_ADDR, 59 #endif 60 #endif 61 #if defined(CONFIG_ARCH_IMX8) 62 [7] = GPIO8_BASE_ADDR, 63 #endif 64 }; 65 66 static int mxc_gpio_direction(unsigned int gpio, 67 enum mxc_gpio_direction direction) 68 { 69 unsigned int port = GPIO_TO_PORT(gpio); 70 struct gpio_regs *regs; 71 u32 l; 72 73 if (port >= ARRAY_SIZE(gpio_ports)) 74 return -1; 75 76 gpio &= 0x1f; 77 78 regs = (struct gpio_regs *)gpio_ports[port]; 79 80 l = readl(®s->gpio_dir); 81 82 switch (direction) { 83 case MXC_GPIO_DIRECTION_OUT: 84 l |= 1 << gpio; 85 break; 86 case MXC_GPIO_DIRECTION_IN: 87 l &= ~(1 << gpio); 88 } 89 writel(l, ®s->gpio_dir); 90 91 return 0; 92 } 93 94 int gpio_set_value(unsigned gpio, int value) 95 { 96 unsigned int port = GPIO_TO_PORT(gpio); 97 struct gpio_regs *regs; 98 u32 l; 99 100 if (port >= ARRAY_SIZE(gpio_ports)) 101 return -1; 102 103 gpio &= 0x1f; 104 105 regs = (struct gpio_regs *)gpio_ports[port]; 106 107 l = readl(®s->gpio_dr); 108 if (value) 109 l |= 1 << gpio; 110 else 111 l &= ~(1 << gpio); 112 writel(l, ®s->gpio_dr); 113 114 return 0; 115 } 116 117 int gpio_get_value(unsigned gpio) 118 { 119 unsigned int port = GPIO_TO_PORT(gpio); 120 struct gpio_regs *regs; 121 u32 val; 122 123 if (port >= ARRAY_SIZE(gpio_ports)) 124 return -1; 125 126 gpio &= 0x1f; 127 128 regs = (struct gpio_regs *)gpio_ports[port]; 129 130 val = (readl(®s->gpio_psr) >> gpio) & 0x01; 131 132 return val; 133 } 134 135 int gpio_request(unsigned gpio, const char *label) 136 { 137 unsigned int port = GPIO_TO_PORT(gpio); 138 if (port >= ARRAY_SIZE(gpio_ports)) 139 return -1; 140 return 0; 141 } 142 143 int gpio_free(unsigned gpio) 144 { 145 return 0; 146 } 147 148 int gpio_direction_input(unsigned gpio) 149 { 150 return mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_IN); 151 } 152 153 int gpio_direction_output(unsigned gpio, int value) 154 { 155 int ret = gpio_set_value(gpio, value); 156 157 if (ret < 0) 158 return ret; 159 160 return mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_OUT); 161 } 162 #endif 163 164 #ifdef CONFIG_DM_GPIO 165 #include <fdtdec.h> 166 static int mxc_gpio_is_output(struct gpio_regs *regs, int offset) 167 { 168 u32 val; 169 170 val = readl(®s->gpio_dir); 171 172 return val & (1 << offset) ? 1 : 0; 173 } 174 175 static void mxc_gpio_bank_direction(struct gpio_regs *regs, int offset, 176 enum mxc_gpio_direction direction) 177 { 178 u32 l; 179 180 l = readl(®s->gpio_dir); 181 182 switch (direction) { 183 case MXC_GPIO_DIRECTION_OUT: 184 l |= 1 << offset; 185 break; 186 case MXC_GPIO_DIRECTION_IN: 187 l &= ~(1 << offset); 188 } 189 writel(l, ®s->gpio_dir); 190 } 191 192 static void mxc_gpio_bank_set_value(struct gpio_regs *regs, int offset, 193 int value) 194 { 195 u32 l; 196 197 l = readl(®s->gpio_dr); 198 if (value) 199 l |= 1 << offset; 200 else 201 l &= ~(1 << offset); 202 writel(l, ®s->gpio_dr); 203 } 204 205 static int mxc_gpio_bank_get_value(struct gpio_regs *regs, int offset) 206 { 207 return (readl(®s->gpio_psr) >> offset) & 0x01; 208 } 209 210 /* set GPIO pin 'gpio' as an input */ 211 static int mxc_gpio_direction_input(struct udevice *dev, unsigned offset) 212 { 213 struct mxc_bank_info *bank = dev_get_priv(dev); 214 215 /* Configure GPIO direction as input. */ 216 mxc_gpio_bank_direction(bank->regs, offset, MXC_GPIO_DIRECTION_IN); 217 218 return 0; 219 } 220 221 /* set GPIO pin 'gpio' as an output, with polarity 'value' */ 222 static int mxc_gpio_direction_output(struct udevice *dev, unsigned offset, 223 int value) 224 { 225 struct mxc_bank_info *bank = dev_get_priv(dev); 226 227 /* Configure GPIO output value. */ 228 mxc_gpio_bank_set_value(bank->regs, offset, value); 229 230 /* Configure GPIO direction as output. */ 231 mxc_gpio_bank_direction(bank->regs, offset, MXC_GPIO_DIRECTION_OUT); 232 233 return 0; 234 } 235 236 /* read GPIO IN value of pin 'gpio' */ 237 static int mxc_gpio_get_value(struct udevice *dev, unsigned offset) 238 { 239 struct mxc_bank_info *bank = dev_get_priv(dev); 240 241 return mxc_gpio_bank_get_value(bank->regs, offset); 242 } 243 244 /* write GPIO OUT value to pin 'gpio' */ 245 static int mxc_gpio_set_value(struct udevice *dev, unsigned offset, 246 int value) 247 { 248 struct mxc_bank_info *bank = dev_get_priv(dev); 249 250 mxc_gpio_bank_set_value(bank->regs, offset, value); 251 252 return 0; 253 } 254 255 static int mxc_gpio_get_function(struct udevice *dev, unsigned offset) 256 { 257 struct mxc_bank_info *bank = dev_get_priv(dev); 258 259 /* GPIOF_FUNC is not implemented yet */ 260 if (mxc_gpio_is_output(bank->regs, offset)) 261 return GPIOF_OUTPUT; 262 else 263 return GPIOF_INPUT; 264 } 265 266 static const struct dm_gpio_ops gpio_mxc_ops = { 267 .direction_input = mxc_gpio_direction_input, 268 .direction_output = mxc_gpio_direction_output, 269 .get_value = mxc_gpio_get_value, 270 .set_value = mxc_gpio_set_value, 271 .get_function = mxc_gpio_get_function, 272 }; 273 274 static int mxc_gpio_probe(struct udevice *dev) 275 { 276 struct mxc_bank_info *bank = dev_get_priv(dev); 277 struct mxc_gpio_plat *plat = dev_get_platdata(dev); 278 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 279 int banknum; 280 char name[18], *str; 281 282 banknum = plat->bank_index; 283 sprintf(name, "GPIO%d_", banknum + 1); 284 str = strdup(name); 285 if (!str) 286 return -ENOMEM; 287 uc_priv->bank_name = str; 288 uc_priv->gpio_count = GPIO_PER_BANK; 289 bank->regs = plat->regs; 290 291 return 0; 292 } 293 294 static int mxc_gpio_bind(struct udevice *dev) 295 { 296 struct mxc_gpio_plat *plat = dev->platdata; 297 fdt_addr_t addr; 298 299 /* 300 * If platdata already exsits, directly return. 301 * Actually only when DT is not supported, platdata 302 * is statically initialized in U_BOOT_DEVICES.Here 303 * will return. 304 */ 305 if (plat) 306 return 0; 307 308 addr = devfdt_get_addr(dev); 309 if (addr == FDT_ADDR_T_NONE) 310 return -EINVAL; 311 312 /* 313 * TODO: 314 * When every board is converted to driver model and DT is supported, 315 * this can be done by auto-alloc feature, but not using calloc 316 * to alloc memory for platdata. 317 * 318 * For example mxc_plat below uses platform data rather than device 319 * tree. 320 * 321 * NOTE: DO NOT COPY this code if you are using device tree. 322 */ 323 plat = calloc(1, sizeof(*plat)); 324 if (!plat) 325 return -ENOMEM; 326 327 plat->regs = (struct gpio_regs *)addr; 328 plat->bank_index = dev->req_seq; 329 dev->platdata = plat; 330 331 return 0; 332 } 333 334 static const struct udevice_id mxc_gpio_ids[] = { 335 { .compatible = "fsl,imx35-gpio" }, 336 { } 337 }; 338 339 U_BOOT_DRIVER(gpio_mxc) = { 340 .name = "gpio_mxc", 341 .id = UCLASS_GPIO, 342 .ops = &gpio_mxc_ops, 343 .probe = mxc_gpio_probe, 344 .priv_auto_alloc_size = sizeof(struct mxc_bank_info), 345 .of_match = mxc_gpio_ids, 346 .bind = mxc_gpio_bind, 347 }; 348 349 #if !CONFIG_IS_ENABLED(OF_CONTROL) 350 static const struct mxc_gpio_plat mxc_plat[] = { 351 { 0, (struct gpio_regs *)GPIO1_BASE_ADDR }, 352 { 1, (struct gpio_regs *)GPIO2_BASE_ADDR }, 353 { 2, (struct gpio_regs *)GPIO3_BASE_ADDR }, 354 #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \ 355 defined(CONFIG_MX53) || defined(CONFIG_MX6) || \ 356 defined(CONFIG_MX8M) || defined(CONFIG_ARCH_IMX8) 357 { 3, (struct gpio_regs *)GPIO4_BASE_ADDR }, 358 #endif 359 #if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6) || \ 360 defined(CONFIG_MX8M) || defined(CONFIG_ARCH_IMX8) 361 { 4, (struct gpio_regs *)GPIO5_BASE_ADDR }, 362 #ifndef CONFIG_MX8M 363 { 5, (struct gpio_regs *)GPIO6_BASE_ADDR }, 364 #endif 365 #endif 366 #if defined(CONFIG_MX53) || defined(CONFIG_MX6) || defined(CONFIG_ARCH_IMX8) 367 { 6, (struct gpio_regs *)GPIO7_BASE_ADDR }, 368 #endif 369 #if defined(CONFIG_ARCH_IMX8) 370 { 7, (struct gpio_regs *)GPIO8_BASE_ADDR }, 371 #endif 372 }; 373 374 U_BOOT_DEVICES(mxc_gpios) = { 375 { "gpio_mxc", &mxc_plat[0] }, 376 { "gpio_mxc", &mxc_plat[1] }, 377 { "gpio_mxc", &mxc_plat[2] }, 378 #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \ 379 defined(CONFIG_MX53) || defined(CONFIG_MX6) || \ 380 defined(CONFIG_MX8M) || defined(CONFIG_ARCH_IMX8) 381 { "gpio_mxc", &mxc_plat[3] }, 382 #endif 383 #if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6) || \ 384 defined(CONFIG_MX8M) || defined(CONFIG_ARCH_IMX8) 385 { "gpio_mxc", &mxc_plat[4] }, 386 #ifndef CONFIG_MX8M 387 { "gpio_mxc", &mxc_plat[5] }, 388 #endif 389 #endif 390 #if defined(CONFIG_MX53) || defined(CONFIG_MX6) || defined(CONFIG_ARCH_IMX8) 391 { "gpio_mxc", &mxc_plat[6] }, 392 #endif 393 #if defined(CONFIG_ARCH_IMX8) 394 { "gpio_mxc", &mxc_plat[7] }, 395 #endif 396 }; 397 #endif 398 #endif 399