gpio-uniphier.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * Copyright (C) 2016-2017 Socionext Inc.
  3. * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
  4. *
  5. * SPDX-License-Identifier: GPL-2.0+
  6. */
  7. #include <common.h>
  8. #include <dm.h>
  9. #include <linux/bitops.h>
  10. #include <linux/io.h>
  11. #include <linux/sizes.h>
  12. #include <linux/errno.h>
  13. #include <asm/global_data.h>
  14. #include <asm/gpio.h>
  15. #define UNIPHIER_GPIO_LINES_PER_BANK 8
  16. #define UNIPHIER_GPIO_PORT_DATA 0x0 /* data */
  17. #define UNIPHIER_GPIO_PORT_DIR 0x4 /* direction (1:in, 0:out) */
  18. #define UNIPHIER_GPIO_IRQ_EN 0x90 /* irq enable */
  19. struct uniphier_gpio_priv {
  20. void __iomem *regs;
  21. };
  22. static unsigned int uniphier_gpio_bank_to_reg(unsigned int bank)
  23. {
  24. unsigned int reg;
  25. reg = (bank + 1) * 8;
  26. /*
  27. * Unfortunately, the GPIO port registers are not contiguous because
  28. * offset 0x90-0x9f is used for IRQ. Add 0x10 when crossing the region.
  29. */
  30. if (reg >= UNIPHIER_GPIO_IRQ_EN)
  31. reg += 0x10;
  32. return reg;
  33. }
  34. static void uniphier_gpio_get_bank_and_mask(unsigned int offset,
  35. unsigned int *bank, u32 *mask)
  36. {
  37. *bank = offset / UNIPHIER_GPIO_LINES_PER_BANK;
  38. *mask = BIT(offset % UNIPHIER_GPIO_LINES_PER_BANK);
  39. }
  40. static void uniphier_gpio_reg_update(struct uniphier_gpio_priv *priv,
  41. unsigned int reg, u32 mask, u32 val)
  42. {
  43. u32 tmp;
  44. tmp = readl(priv->regs + reg);
  45. tmp &= ~mask;
  46. tmp |= mask & val;
  47. writel(tmp, priv->regs + reg);
  48. }
  49. static void uniphier_gpio_bank_write(struct udevice *dev, unsigned int bank,
  50. unsigned int reg, u32 mask, u32 val)
  51. {
  52. struct uniphier_gpio_priv *priv = dev_get_priv(dev);
  53. if (!mask)
  54. return;
  55. uniphier_gpio_reg_update(priv, uniphier_gpio_bank_to_reg(bank) + reg,
  56. mask, val);
  57. }
  58. static void uniphier_gpio_offset_write(struct udevice *dev, unsigned int offset,
  59. unsigned int reg, int val)
  60. {
  61. unsigned int bank;
  62. u32 mask;
  63. uniphier_gpio_get_bank_and_mask(offset, &bank, &mask);
  64. uniphier_gpio_bank_write(dev, bank, reg, mask, val ? mask : 0);
  65. }
  66. static int uniphier_gpio_offset_read(struct udevice *dev,
  67. unsigned int offset, unsigned int reg)
  68. {
  69. struct uniphier_gpio_priv *priv = dev_get_priv(dev);
  70. unsigned int bank, reg_offset;
  71. u32 mask;
  72. uniphier_gpio_get_bank_and_mask(offset, &bank, &mask);
  73. reg_offset = uniphier_gpio_bank_to_reg(bank) + reg;
  74. return !!(readl(priv->regs + reg_offset) & mask);
  75. }
  76. static int uniphier_gpio_get_function(struct udevice *dev, unsigned int offset)
  77. {
  78. return uniphier_gpio_offset_read(dev, offset, UNIPHIER_GPIO_PORT_DIR) ?
  79. GPIOF_INPUT : GPIOF_OUTPUT;
  80. }
  81. static int uniphier_gpio_direction_input(struct udevice *dev,
  82. unsigned int offset)
  83. {
  84. uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_PORT_DIR, 1);
  85. return 0;
  86. }
  87. static int uniphier_gpio_direction_output(struct udevice *dev,
  88. unsigned int offset, int value)
  89. {
  90. uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_PORT_DATA, value);
  91. uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_PORT_DIR, 0);
  92. return 0;
  93. }
  94. static int uniphier_gpio_get_value(struct udevice *dev, unsigned int offset)
  95. {
  96. return uniphier_gpio_offset_read(dev, offset, UNIPHIER_GPIO_PORT_DATA);
  97. }
  98. static int uniphier_gpio_set_value(struct udevice *dev,
  99. unsigned int offset, int value)
  100. {
  101. uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_PORT_DATA, value);
  102. return 0;
  103. }
  104. static const struct dm_gpio_ops uniphier_gpio_ops = {
  105. .direction_input = uniphier_gpio_direction_input,
  106. .direction_output = uniphier_gpio_direction_output,
  107. .get_value = uniphier_gpio_get_value,
  108. .set_value = uniphier_gpio_set_value,
  109. .get_function = uniphier_gpio_get_function,
  110. };
  111. static int uniphier_gpio_probe(struct udevice *dev)
  112. {
  113. struct uniphier_gpio_priv *priv = dev_get_priv(dev);
  114. struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
  115. fdt_addr_t addr;
  116. addr = devfdt_get_addr(dev);
  117. if (addr == FDT_ADDR_T_NONE)
  118. return -EINVAL;
  119. priv->regs = devm_ioremap(dev, addr, SZ_512);
  120. if (!priv->regs)
  121. return -ENOMEM;
  122. uc_priv->gpio_count = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
  123. "ngpios", 0);
  124. return 0;
  125. }
  126. static const struct udevice_id uniphier_gpio_match[] = {
  127. { .compatible = "socionext,uniphier-gpio" },
  128. { /* sentinel */ }
  129. };
  130. U_BOOT_DRIVER(uniphier_gpio) = {
  131. .name = "uniphier-gpio",
  132. .id = UCLASS_GPIO,
  133. .of_match = uniphier_gpio_match,
  134. .probe = uniphier_gpio_probe,
  135. .priv_auto_alloc_size = sizeof(struct uniphier_gpio_priv),
  136. .ops = &uniphier_gpio_ops,
  137. };