tegra186_gpio.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2010-2016, NVIDIA CORPORATION.
  4. * (based on tegra_gpio.c)
  5. */
  6. #include <common.h>
  7. #include <dm.h>
  8. #include <malloc.h>
  9. #include <errno.h>
  10. #include <fdtdec.h>
  11. #include <asm/io.h>
  12. #include <asm/bitops.h>
  13. #include <asm/gpio.h>
  14. #include <dm/device-internal.h>
  15. #include <dt-bindings/gpio/gpio.h>
  16. #include "tegra186_gpio_priv.h"
  17. struct tegra186_gpio_port_data {
  18. const char *name;
  19. uint32_t offset;
  20. };
  21. struct tegra186_gpio_ctlr_data {
  22. const struct tegra186_gpio_port_data *ports;
  23. uint32_t port_count;
  24. };
  25. struct tegra186_gpio_plat {
  26. const char *name;
  27. uint32_t *regs;
  28. };
  29. static uint32_t *tegra186_gpio_reg(struct udevice *dev, uint32_t reg,
  30. uint32_t gpio)
  31. {
  32. struct tegra186_gpio_plat *plat = dev_get_plat(dev);
  33. uint32_t index = (reg + (gpio * TEGRA186_GPIO_PER_GPIO_STRIDE)) / 4;
  34. return &(plat->regs[index]);
  35. }
  36. static int tegra186_gpio_set_out(struct udevice *dev, unsigned offset,
  37. bool output)
  38. {
  39. uint32_t *reg;
  40. uint32_t rval;
  41. reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_OUTPUT_CONTROL, offset);
  42. rval = readl(reg);
  43. if (output)
  44. rval &= ~TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED;
  45. else
  46. rval |= TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED;
  47. writel(rval, reg);
  48. reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_ENABLE_CONFIG, offset);
  49. rval = readl(reg);
  50. if (output)
  51. rval |= TEGRA186_GPIO_ENABLE_CONFIG_OUT;
  52. else
  53. rval &= ~TEGRA186_GPIO_ENABLE_CONFIG_OUT;
  54. rval |= TEGRA186_GPIO_ENABLE_CONFIG_ENABLE;
  55. writel(rval, reg);
  56. return 0;
  57. }
  58. static int tegra186_gpio_set_val(struct udevice *dev, unsigned offset, bool val)
  59. {
  60. uint32_t *reg;
  61. uint32_t rval;
  62. reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_OUTPUT_VALUE, offset);
  63. rval = readl(reg);
  64. if (val)
  65. rval |= TEGRA186_GPIO_OUTPUT_VALUE_HIGH;
  66. else
  67. rval &= ~TEGRA186_GPIO_OUTPUT_VALUE_HIGH;
  68. writel(rval, reg);
  69. return 0;
  70. }
  71. static int tegra186_gpio_direction_input(struct udevice *dev, unsigned offset)
  72. {
  73. return tegra186_gpio_set_out(dev, offset, false);
  74. }
  75. static int tegra186_gpio_direction_output(struct udevice *dev, unsigned offset,
  76. int value)
  77. {
  78. int ret;
  79. ret = tegra186_gpio_set_val(dev, offset, value != 0);
  80. if (ret)
  81. return ret;
  82. return tegra186_gpio_set_out(dev, offset, true);
  83. }
  84. static int tegra186_gpio_get_value(struct udevice *dev, unsigned offset)
  85. {
  86. uint32_t *reg;
  87. uint32_t rval;
  88. reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_ENABLE_CONFIG, offset);
  89. rval = readl(reg);
  90. if (rval & TEGRA186_GPIO_ENABLE_CONFIG_OUT)
  91. reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_OUTPUT_VALUE,
  92. offset);
  93. else
  94. reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_INPUT, offset);
  95. rval = readl(reg);
  96. return !!rval;
  97. }
  98. static int tegra186_gpio_set_value(struct udevice *dev, unsigned offset,
  99. int value)
  100. {
  101. return tegra186_gpio_set_val(dev, offset, value != 0);
  102. }
  103. static int tegra186_gpio_get_function(struct udevice *dev, unsigned offset)
  104. {
  105. uint32_t *reg;
  106. uint32_t rval;
  107. reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_ENABLE_CONFIG, offset);
  108. rval = readl(reg);
  109. if (rval & TEGRA186_GPIO_ENABLE_CONFIG_OUT)
  110. return GPIOF_OUTPUT;
  111. else
  112. return GPIOF_INPUT;
  113. }
  114. static int tegra186_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
  115. struct ofnode_phandle_args *args)
  116. {
  117. int gpio, port, ret;
  118. gpio = args->args[0];
  119. port = gpio / TEGRA186_GPIO_PER_GPIO_COUNT;
  120. ret = device_get_child(dev, port, &desc->dev);
  121. if (ret)
  122. return ret;
  123. desc->offset = gpio % TEGRA186_GPIO_PER_GPIO_COUNT;
  124. desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
  125. return 0;
  126. }
  127. static const struct dm_gpio_ops tegra186_gpio_ops = {
  128. .direction_input = tegra186_gpio_direction_input,
  129. .direction_output = tegra186_gpio_direction_output,
  130. .get_value = tegra186_gpio_get_value,
  131. .set_value = tegra186_gpio_set_value,
  132. .get_function = tegra186_gpio_get_function,
  133. .xlate = tegra186_gpio_xlate,
  134. };
  135. /**
  136. * We have a top-level GPIO device with no actual GPIOs. It has a child device
  137. * for each port within the controller.
  138. */
  139. static int tegra186_gpio_bind(struct udevice *parent)
  140. {
  141. struct tegra186_gpio_plat *parent_plat = dev_get_plat(parent);
  142. struct tegra186_gpio_ctlr_data *ctlr_data =
  143. (struct tegra186_gpio_ctlr_data *)dev_get_driver_data(parent);
  144. uint32_t *regs;
  145. int port, ret;
  146. /* If this is a child device, there is nothing to do here */
  147. if (parent_plat)
  148. return 0;
  149. regs = (uint32_t *)devfdt_get_addr_name(parent, "gpio");
  150. if (regs == (uint32_t *)FDT_ADDR_T_NONE)
  151. return -EINVAL;
  152. for (port = 0; port < ctlr_data->port_count; port++) {
  153. struct tegra186_gpio_plat *plat;
  154. struct udevice *dev;
  155. plat = calloc(1, sizeof(*plat));
  156. if (!plat)
  157. return -ENOMEM;
  158. plat->name = ctlr_data->ports[port].name;
  159. plat->regs = &(regs[ctlr_data->ports[port].offset / 4]);
  160. ret = device_bind(parent, parent->driver, plat->name, plat,
  161. dev_ofnode(parent), &dev);
  162. if (ret)
  163. return ret;
  164. }
  165. return 0;
  166. }
  167. static int tegra186_gpio_probe(struct udevice *dev)
  168. {
  169. struct tegra186_gpio_plat *plat = dev_get_plat(dev);
  170. struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
  171. /* Only child devices have ports */
  172. if (!plat)
  173. return 0;
  174. uc_priv->gpio_count = TEGRA186_GPIO_PER_GPIO_COUNT;
  175. uc_priv->bank_name = plat->name;
  176. return 0;
  177. }
  178. static const struct tegra186_gpio_port_data tegra186_gpio_main_ports[] = {
  179. {"A", 0x2000},
  180. {"B", 0x3000},
  181. {"C", 0x3200},
  182. {"D", 0x3400},
  183. {"E", 0x2200},
  184. {"F", 0x2400},
  185. {"G", 0x4200},
  186. {"H", 0x1000},
  187. {"I", 0x0800},
  188. {"J", 0x5000},
  189. {"K", 0x5200},
  190. {"L", 0x1200},
  191. {"M", 0x5600},
  192. {"N", 0x0000},
  193. {"O", 0x0200},
  194. {"P", 0x4000},
  195. {"Q", 0x0400},
  196. {"R", 0x0a00},
  197. {"T", 0x0600},
  198. {"X", 0x1400},
  199. {"Y", 0x1600},
  200. {"BB", 0x2600},
  201. {"CC", 0x5400},
  202. };
  203. static const struct tegra186_gpio_ctlr_data tegra186_gpio_main_data = {
  204. .ports = tegra186_gpio_main_ports,
  205. .port_count = ARRAY_SIZE(tegra186_gpio_main_ports),
  206. };
  207. static const struct tegra186_gpio_port_data tegra186_gpio_aon_ports[] = {
  208. {"S", 0x0200},
  209. {"U", 0x0400},
  210. {"V", 0x0800},
  211. {"W", 0x0a00},
  212. {"Z", 0x0e00},
  213. {"AA", 0x0c00},
  214. {"EE", 0x0600},
  215. {"FF", 0x0000},
  216. };
  217. static const struct tegra186_gpio_ctlr_data tegra186_gpio_aon_data = {
  218. .ports = tegra186_gpio_aon_ports,
  219. .port_count = ARRAY_SIZE(tegra186_gpio_aon_ports),
  220. };
  221. static const struct udevice_id tegra186_gpio_ids[] = {
  222. {
  223. .compatible = "nvidia,tegra186-gpio",
  224. .data = (ulong)&tegra186_gpio_main_data,
  225. },
  226. {
  227. .compatible = "nvidia,tegra186-gpio-aon",
  228. .data = (ulong)&tegra186_gpio_aon_data,
  229. },
  230. { }
  231. };
  232. U_BOOT_DRIVER(tegra186_gpio) = {
  233. .name = "tegra186_gpio",
  234. .id = UCLASS_GPIO,
  235. .of_match = tegra186_gpio_ids,
  236. .bind = tegra186_gpio_bind,
  237. .probe = tegra186_gpio_probe,
  238. .ops = &tegra186_gpio_ops,
  239. };