sl28cpld-gpio.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * GPIO driver for the sl28cpld
  4. *
  5. * Copyright (c) 2021 Michael Walle <michael@walle.cc>
  6. */
  7. #include <common.h>
  8. #include <dm.h>
  9. #include <asm/gpio.h>
  10. #include <sl28cpld.h>
  11. /* GPIO flavor */
  12. #define SL28CPLD_GPIO_DIR 0x00
  13. #define SL28CPLD_GPIO_OUT 0x01
  14. #define SL28CPLD_GPIO_IN 0x02
  15. /* input-only flavor */
  16. #define SL28CPLD_GPI_IN 0x00
  17. /* output-only flavor */
  18. #define SL28CPLD_GPO_OUT 0x00
  19. enum {
  20. SL28CPLD_GPIO,
  21. SL28CPLD_GPI,
  22. SL28CPLD_GPO,
  23. };
  24. static int sl28cpld_gpio_get_value(struct udevice *dev, unsigned int gpio)
  25. {
  26. ulong type = dev_get_driver_data(dev);
  27. int val, reg;
  28. switch (type) {
  29. case SL28CPLD_GPIO:
  30. reg = SL28CPLD_GPIO_IN;
  31. break;
  32. case SL28CPLD_GPI:
  33. reg = SL28CPLD_GPI_IN;
  34. break;
  35. case SL28CPLD_GPO:
  36. /* we are output only, thus just return the output value */
  37. reg = SL28CPLD_GPO_OUT;
  38. break;
  39. default:
  40. return -EINVAL;
  41. }
  42. val = sl28cpld_read(dev, reg);
  43. return val < 0 ? val : !!(val & BIT(gpio));
  44. }
  45. static int sl28cpld_gpio_set_value(struct udevice *dev, unsigned int gpio,
  46. int value)
  47. {
  48. ulong type = dev_get_driver_data(dev);
  49. uint reg;
  50. switch (type) {
  51. case SL28CPLD_GPIO:
  52. reg = SL28CPLD_GPIO_OUT;
  53. break;
  54. case SL28CPLD_GPO:
  55. reg = SL28CPLD_GPO_OUT;
  56. break;
  57. case SL28CPLD_GPI:
  58. default:
  59. return -EINVAL;
  60. }
  61. if (value)
  62. return sl28cpld_update(dev, reg, 0, BIT(gpio));
  63. else
  64. return sl28cpld_update(dev, reg, BIT(gpio), 0);
  65. }
  66. static int sl28cpld_gpio_direction_input(struct udevice *dev, unsigned int gpio)
  67. {
  68. ulong type = dev_get_driver_data(dev);
  69. switch (type) {
  70. case SL28CPLD_GPI:
  71. return 0;
  72. case SL28CPLD_GPIO:
  73. return sl28cpld_update(dev, SL28CPLD_GPIO_DIR, BIT(gpio), 0);
  74. case SL28CPLD_GPO:
  75. default:
  76. return -EINVAL;
  77. }
  78. }
  79. static int sl28cpld_gpio_direction_output(struct udevice *dev,
  80. unsigned int gpio, int value)
  81. {
  82. ulong type = dev_get_driver_data(dev);
  83. int ret;
  84. /* set_value() will report an error if we are input-only */
  85. ret = sl28cpld_gpio_set_value(dev, gpio, value);
  86. if (ret)
  87. return ret;
  88. if (type == SL28CPLD_GPIO)
  89. return sl28cpld_update(dev, SL28CPLD_GPIO_DIR, 0, BIT(gpio));
  90. return 0;
  91. }
  92. static int sl28cpld_gpio_get_function(struct udevice *dev, unsigned int gpio)
  93. {
  94. ulong type = dev_get_driver_data(dev);
  95. int val;
  96. switch (type) {
  97. case SL28CPLD_GPIO:
  98. val = sl28cpld_read(dev, SL28CPLD_GPIO_DIR);
  99. if (val < 0)
  100. return val;
  101. if (val & BIT(gpio))
  102. return GPIOF_OUTPUT;
  103. else
  104. return GPIOF_INPUT;
  105. case SL28CPLD_GPI:
  106. return GPIOF_INPUT;
  107. case SL28CPLD_GPO:
  108. return GPIOF_OUTPUT;
  109. default:
  110. return -EINVAL;
  111. }
  112. }
  113. static const struct dm_gpio_ops sl28cpld_gpio_ops = {
  114. .direction_input = sl28cpld_gpio_direction_input,
  115. .direction_output = sl28cpld_gpio_direction_output,
  116. .get_value = sl28cpld_gpio_get_value,
  117. .set_value = sl28cpld_gpio_set_value,
  118. .get_function = sl28cpld_gpio_get_function,
  119. };
  120. static int sl28cpld_gpio_probe(struct udevice *dev)
  121. {
  122. struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
  123. uc_priv->gpio_count = 8;
  124. uc_priv->bank_name = dev_read_name(dev);
  125. return 0;
  126. }
  127. static const struct udevice_id sl28cpld_gpio_ids[] = {
  128. { .compatible = "kontron,sl28cpld-gpio", .data = SL28CPLD_GPIO},
  129. { .compatible = "kontron,sl28cpld-gpo", .data = SL28CPLD_GPO},
  130. { .compatible = "kontron,sl28cpld-gpi", .data = SL28CPLD_GPI},
  131. { }
  132. };
  133. U_BOOT_DRIVER(sl28cpld_gpio) = {
  134. .name = "sl28cpld_gpio",
  135. .id = UCLASS_GPIO,
  136. .of_match = sl28cpld_gpio_ids,
  137. .probe = sl28cpld_gpio_probe,
  138. .ops = &sl28cpld_gpio_ops,
  139. };