gazerbeam.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * (C) Copyright 2017
  4. * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
  5. */
  6. #include <common.h>
  7. #include <dm.h>
  8. #include <board.h>
  9. #include <i2c.h>
  10. #include <asm/gpio.h>
  11. #include "gazerbeam.h"
  12. /* Sequence number of I2C bus that holds the GPIO expanders */
  13. static const int I2C_BUS_SEQ_NO = 1;
  14. /* I2C address of SC/MC2 expander */
  15. static const int MC2_EXPANDER_ADDR = 0x20;
  16. /* I2C address of MC4 expander */
  17. static const int MC4_EXPANDER_ADDR = 0x22;
  18. /* Number of the GPIO to read the SC data from */
  19. static const int SC_GPIO_NO;
  20. /* Number of the GPIO to read the CON data from */
  21. static const int CON_GPIO_NO = 1;
  22. /**
  23. * struct board_gazerbeam_priv - Private data structure for the gazerbeam board
  24. * driver.
  25. * @reset_gpios: GPIOs for the board's reset GPIOs.
  26. * @var_gpios: GPIOs for the board's hardware variant GPIOs
  27. * @ver_gpios: GPIOs for the board's hardware version GPIOs
  28. * @variant: Container for the board's hardware variant (CON/CPU)
  29. * @multichannel: Container for the board's multichannel variant (MC4/MC2/SC)
  30. * @hwversion: Container for the board's hardware version
  31. */
  32. struct board_gazerbeam_priv {
  33. struct gpio_desc reset_gpios[2];
  34. struct gpio_desc var_gpios[2];
  35. struct gpio_desc ver_gpios[4];
  36. int variant;
  37. int multichannel;
  38. int hwversion;
  39. };
  40. /**
  41. * _read_board_variant_data() - Read variant information from the hardware.
  42. * @dev: The board device for which to determine the multichannel and device
  43. * type information.
  44. *
  45. * The data read from the board's hardware (mostly hard-wired GPIOs) is stored
  46. * in the private data structure of the driver to be used by other driver
  47. * methods.
  48. *
  49. * Return: 0 if OK, -ve on error.
  50. */
  51. static int _read_board_variant_data(struct udevice *dev)
  52. {
  53. struct board_gazerbeam_priv *priv = dev_get_priv(dev);
  54. struct udevice *i2c_bus;
  55. struct udevice *dummy;
  56. char *listname;
  57. int mc4, mc2, sc, con;
  58. int gpio_num;
  59. int res;
  60. res = uclass_get_device_by_seq(UCLASS_I2C, I2C_BUS_SEQ_NO, &i2c_bus);
  61. if (res) {
  62. debug("%s: Could not get I2C bus %d (err = %d)\n",
  63. dev->name, I2C_BUS_SEQ_NO, res);
  64. return res;
  65. }
  66. if (!i2c_bus) {
  67. debug("%s: Could not get I2C bus %d\n",
  68. dev->name, I2C_BUS_SEQ_NO);
  69. return -EIO;
  70. }
  71. mc2 = !dm_i2c_probe(i2c_bus, MC2_EXPANDER_ADDR, 0, &dummy);
  72. mc4 = !dm_i2c_probe(i2c_bus, MC4_EXPANDER_ADDR, 0, &dummy);
  73. if (mc2 && mc4) {
  74. debug("%s: Board hardware configuration inconsistent.\n",
  75. dev->name);
  76. return -EINVAL;
  77. }
  78. listname = mc2 ? "var-gpios-mc2" : "var-gpios-mc4";
  79. gpio_num = gpio_request_list_by_name(dev, listname, priv->var_gpios,
  80. ARRAY_SIZE(priv->var_gpios),
  81. GPIOD_IS_IN);
  82. if (gpio_num < 0) {
  83. debug("%s: Requesting gpio list %s failed (err = %d).\n",
  84. dev->name, listname, gpio_num);
  85. return gpio_num;
  86. }
  87. sc = dm_gpio_get_value(&priv->var_gpios[SC_GPIO_NO]);
  88. if (sc < 0) {
  89. debug("%s: Error while reading 'sc' GPIO (err = %d)",
  90. dev->name, sc);
  91. return sc;
  92. }
  93. con = dm_gpio_get_value(&priv->var_gpios[CON_GPIO_NO]);
  94. if (con < 0) {
  95. debug("%s: Error while reading 'con' GPIO (err = %d)",
  96. dev->name, con);
  97. return con;
  98. }
  99. if ((sc && mc2) || (sc && mc4) || (!sc && !mc2 && !mc4)) {
  100. debug("%s: Board hardware configuration inconsistent.\n",
  101. dev->name);
  102. return -EINVAL;
  103. }
  104. priv->variant = con ? VAR_CON : VAR_CPU;
  105. priv->multichannel = mc4 ? 4 : (mc2 ? 2 : (sc ? 1 : 0));
  106. return 0;
  107. }
  108. /**
  109. * _read_hwversion() - Read the hardware version from the board.
  110. * @dev: The board device for which to read the hardware version.
  111. *
  112. * The hardware version read from the board (from hard-wired GPIOs) is stored
  113. * in the private data structure of the driver to be used by other driver
  114. * methods.
  115. *
  116. * Return: 0 if OK, -ve on error.
  117. */
  118. static int _read_hwversion(struct udevice *dev)
  119. {
  120. struct board_gazerbeam_priv *priv = dev_get_priv(dev);
  121. int res;
  122. res = gpio_request_list_by_name(dev, "ver-gpios", priv->ver_gpios,
  123. ARRAY_SIZE(priv->ver_gpios),
  124. GPIOD_IS_IN);
  125. if (res < 0) {
  126. debug("%s: Error getting GPIO list 'ver-gpios' (err = %d)\n",
  127. dev->name, res);
  128. return -ENODEV;
  129. }
  130. res = dm_gpio_get_values_as_int(priv->ver_gpios,
  131. ARRAY_SIZE(priv->ver_gpios));
  132. if (res < 0) {
  133. debug("%s: Error reading HW version from expander (err = %d)\n",
  134. dev->name, res);
  135. return res;
  136. }
  137. priv->hwversion = res;
  138. res = gpio_free_list(dev, priv->ver_gpios, ARRAY_SIZE(priv->ver_gpios));
  139. if (res < 0) {
  140. debug("%s: Error freeing HW version GPIO list (err = %d)\n",
  141. dev->name, res);
  142. return res;
  143. }
  144. return 0;
  145. }
  146. static int board_gazerbeam_detect(struct udevice *dev)
  147. {
  148. int res;
  149. res = _read_board_variant_data(dev);
  150. if (res) {
  151. debug("%s: Error reading multichannel variant (err = %d)\n",
  152. dev->name, res);
  153. return res;
  154. }
  155. res = _read_hwversion(dev);
  156. if (res) {
  157. debug("%s: Error reading hardware version (err = %d)\n",
  158. dev->name, res);
  159. return res;
  160. }
  161. return 0;
  162. }
  163. static int board_gazerbeam_get_int(struct udevice *dev, int id, int *val)
  164. {
  165. struct board_gazerbeam_priv *priv = dev_get_priv(dev);
  166. switch (id) {
  167. case BOARD_MULTICHANNEL:
  168. *val = priv->multichannel;
  169. break;
  170. case BOARD_VARIANT:
  171. *val = priv->variant;
  172. break;
  173. case BOARD_HWVERSION:
  174. *val = priv->hwversion;
  175. break;
  176. default:
  177. debug("%s: Integer value %d unknown\n", dev->name, id);
  178. return -EINVAL;
  179. }
  180. return 0;
  181. }
  182. static const struct udevice_id board_gazerbeam_ids[] = {
  183. { .compatible = "gdsys,board_gazerbeam" },
  184. { /* sentinel */ }
  185. };
  186. static const struct board_ops board_gazerbeam_ops = {
  187. .detect = board_gazerbeam_detect,
  188. .get_int = board_gazerbeam_get_int,
  189. };
  190. static int board_gazerbeam_probe(struct udevice *dev)
  191. {
  192. struct board_gazerbeam_priv *priv = dev_get_priv(dev);
  193. int gpio_num, i;
  194. gpio_num = gpio_request_list_by_name(dev, "reset-gpios",
  195. priv->reset_gpios,
  196. ARRAY_SIZE(priv->reset_gpios),
  197. GPIOD_IS_OUT);
  198. if (gpio_num < 0) {
  199. debug("%s: Error getting GPIO list 'reset-gpios' (err = %d)\n",
  200. dev->name, gpio_num);
  201. return gpio_num;
  202. }
  203. /* Set startup-finished GPIOs */
  204. for (i = 0; i < ARRAY_SIZE(priv->reset_gpios); i++) {
  205. int res = dm_gpio_set_value(&priv->reset_gpios[i], 0);
  206. if (res) {
  207. debug("%s: Error while setting GPIO %d (err = %d)\n",
  208. dev->name, i, res);
  209. return res;
  210. }
  211. }
  212. return 0;
  213. }
  214. U_BOOT_DRIVER(board_gazerbeam) = {
  215. .name = "board_gazerbeam",
  216. .id = UCLASS_BOARD,
  217. .of_match = board_gazerbeam_ids,
  218. .ops = &board_gazerbeam_ops,
  219. .priv_auto_alloc_size = sizeof(struct board_gazerbeam_priv),
  220. .probe = board_gazerbeam_probe,
  221. };