gpio-uniphier.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /*
  2. * Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com>
  3. *
  4. * SPDX-License-Identifier: GPL-2.0+
  5. */
  6. #include <common.h>
  7. #include <dm/device.h>
  8. #include <mapmem.h>
  9. #include <linux/bitops.h>
  10. #include <linux/io.h>
  11. #include <asm/errno.h>
  12. #include <asm/gpio.h>
  13. #define UNIPHIER_GPIO_PORTS_PER_BANK 8
  14. #define UNIPHIER_GPIO_REG_DATA 0 /* data */
  15. #define UNIPHIER_GPIO_REG_DIR 4 /* direction (1:in, 0:out) */
  16. struct uniphier_gpio_priv {
  17. void __iomem *base;
  18. char bank_name[16];
  19. };
  20. static void uniphier_gpio_offset_write(struct udevice *dev, unsigned offset,
  21. unsigned reg, int value)
  22. {
  23. struct uniphier_gpio_priv *priv = dev_get_priv(dev);
  24. u32 tmp;
  25. tmp = readl(priv->base + reg);
  26. if (value)
  27. tmp |= BIT(offset);
  28. else
  29. tmp &= ~BIT(offset);
  30. writel(tmp, priv->base + reg);
  31. }
  32. static int uniphier_gpio_offset_read(struct udevice *dev, unsigned offset,
  33. unsigned reg)
  34. {
  35. struct uniphier_gpio_priv *priv = dev_get_priv(dev);
  36. return !!(readl(priv->base + reg) & BIT(offset));
  37. }
  38. static int uniphier_gpio_direction_input(struct udevice *dev, unsigned offset)
  39. {
  40. uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_REG_DIR, 1);
  41. return 0;
  42. }
  43. static int uniphier_gpio_direction_output(struct udevice *dev, unsigned offset,
  44. int value)
  45. {
  46. uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_REG_DATA, value);
  47. uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_REG_DIR, 0);
  48. return 0;
  49. }
  50. static int uniphier_gpio_get_value(struct udevice *dev, unsigned offset)
  51. {
  52. return uniphier_gpio_offset_read(dev, offset, UNIPHIER_GPIO_REG_DATA);
  53. }
  54. static int uniphier_gpio_set_value(struct udevice *dev, unsigned offset,
  55. int value)
  56. {
  57. uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_REG_DATA, value);
  58. return 0;
  59. }
  60. static int uniphier_gpio_get_function(struct udevice *dev, unsigned offset)
  61. {
  62. return uniphier_gpio_offset_read(dev, offset, UNIPHIER_GPIO_REG_DIR) ?
  63. GPIOF_INPUT : GPIOF_OUTPUT;
  64. }
  65. static const struct dm_gpio_ops uniphier_gpio_ops = {
  66. .direction_input = uniphier_gpio_direction_input,
  67. .direction_output = uniphier_gpio_direction_output,
  68. .get_value = uniphier_gpio_get_value,
  69. .set_value = uniphier_gpio_set_value,
  70. .get_function = uniphier_gpio_get_function,
  71. };
  72. static int uniphier_gpio_probe(struct udevice *dev)
  73. {
  74. struct uniphier_gpio_priv *priv = dev_get_priv(dev);
  75. struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
  76. DECLARE_GLOBAL_DATA_PTR;
  77. fdt_addr_t addr;
  78. fdt_size_t size;
  79. unsigned int tmp;
  80. addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg",
  81. &size);
  82. if (addr == FDT_ADDR_T_NONE)
  83. return -EINVAL;
  84. priv->base = map_sysmem(addr, size);
  85. if (!priv->base)
  86. return -ENOMEM;
  87. uc_priv->gpio_count = UNIPHIER_GPIO_PORTS_PER_BANK;
  88. tmp = (addr & 0xfff);
  89. /* Unfortunately, there is a register hole at offset 0x90-0x9f. */
  90. if (tmp > 0x90)
  91. tmp -= 0x10;
  92. snprintf(priv->bank_name, sizeof(priv->bank_name) - 1,
  93. "port%d-", (tmp - 8) / 8);
  94. uc_priv->bank_name = priv->bank_name;
  95. return 0;
  96. }
  97. static int uniphier_gpio_remove(struct udevice *dev)
  98. {
  99. struct uniphier_gpio_priv *priv = dev_get_priv(dev);
  100. unmap_sysmem(priv->base);
  101. return 0;
  102. }
  103. /* .data = the number of GPIO banks */
  104. static const struct udevice_id uniphier_gpio_match[] = {
  105. { .compatible = "socionext,uniphier-gpio" },
  106. { /* sentinel */ }
  107. };
  108. U_BOOT_DRIVER(uniphier_gpio) = {
  109. .name = "uniphier_gpio",
  110. .id = UCLASS_GPIO,
  111. .of_match = uniphier_gpio_match,
  112. .probe = uniphier_gpio_probe,
  113. .remove = uniphier_gpio_remove,
  114. .priv_auto_alloc_size = sizeof(struct uniphier_gpio_priv),
  115. .ops = &uniphier_gpio_ops,
  116. };