spmi-sandbox.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Sample SPMI bus driver
  4. *
  5. * It emulates bus with single pm8916-like pmic that has only GPIO reigsters.
  6. *
  7. * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
  8. */
  9. #include <common.h>
  10. #include <dm.h>
  11. #include <errno.h>
  12. #include <spmi/spmi.h>
  13. #include <asm/gpio.h>
  14. #include <asm/io.h>
  15. #define EMUL_GPIO_PID_START 0xC0
  16. #define EMUL_GPIO_PID_END 0xC3
  17. #define EMUL_GPIO_COUNT 4
  18. #define EMUL_GPIO_REG_END 0x46 /* Last valid register */
  19. #define EMUL_PERM_R 0x1
  20. #define EMUL_PERM_W 0x2
  21. #define EMUL_PERM_RW (EMUL_PERM_R | EMUL_PERM_W)
  22. struct sandbox_emul_fake_regs {
  23. u8 value;
  24. u8 access_mask;
  25. u8 perms; /* Access permissions */
  26. };
  27. struct sandbox_emul_gpio {
  28. /* Fake registers - need one more entry as REG_END is valid address. */
  29. struct sandbox_emul_fake_regs r[EMUL_GPIO_REG_END + 1];
  30. };
  31. struct sandbox_spmi_priv {
  32. struct sandbox_emul_gpio gpios[EMUL_GPIO_COUNT];
  33. };
  34. /* Check if valid register was requested */
  35. static bool check_address_valid(int usid, int pid, int off)
  36. {
  37. if (usid != 0)
  38. return false;
  39. if (pid < EMUL_GPIO_PID_START || pid > EMUL_GPIO_PID_END)
  40. return false;
  41. if (off > EMUL_GPIO_REG_END)
  42. return false;
  43. return true;
  44. }
  45. static int sandbox_spmi_write(struct udevice *dev, int usid, int pid, int off,
  46. uint8_t val)
  47. {
  48. struct sandbox_spmi_priv *priv = dev_get_priv(dev);
  49. struct sandbox_emul_fake_regs *regs;
  50. if (!check_address_valid(usid, pid, off))
  51. return -EIO;
  52. regs = priv->gpios[pid & 0x3].r; /* Last 3 bits of pid are gpio # */
  53. switch (off) {
  54. case 0x40: /* Control */
  55. val &= regs[off].access_mask;
  56. if (((val & 0x30) == 0x10) || ((val & 0x30) == 0x20)) {
  57. /* out/inout - set status register */
  58. regs[0x8].value &= ~0x1;
  59. regs[0x8].value |= val & 0x1;
  60. }
  61. break;
  62. default:
  63. if (regs[off].perms & EMUL_PERM_W)
  64. regs[off].value = val & regs[off].access_mask;
  65. }
  66. return 0;
  67. }
  68. static int sandbox_spmi_read(struct udevice *dev, int usid, int pid, int off)
  69. {
  70. struct sandbox_spmi_priv *priv = dev_get_priv(dev);
  71. struct sandbox_emul_fake_regs *regs;
  72. if (!check_address_valid(usid, pid, off))
  73. return -EIO;
  74. regs = priv->gpios[pid & 0x3].r; /* Last 3 bits of pid are gpio # */
  75. if (regs[0x46].value == 0) /* Block disabled */
  76. return 0;
  77. switch (off) {
  78. case 0x8: /* Status */
  79. if (regs[0x46].value == 0) /* Block disabled */
  80. return 0;
  81. return regs[off].value;
  82. default:
  83. if (regs[off].perms & EMUL_PERM_R)
  84. return regs[off].value;
  85. else
  86. return 0;
  87. }
  88. }
  89. static struct dm_spmi_ops sandbox_spmi_ops = {
  90. .read = sandbox_spmi_read,
  91. .write = sandbox_spmi_write,
  92. };
  93. static int sandbox_spmi_probe(struct udevice *dev)
  94. {
  95. struct sandbox_spmi_priv *priv = dev_get_priv(dev);
  96. int i;
  97. for (i = 0; i < EMUL_GPIO_COUNT; ++i) {
  98. struct sandbox_emul_fake_regs *regs = priv->gpios[i].r;
  99. regs[4].perms = EMUL_PERM_R;
  100. regs[4].value = 0x10;
  101. regs[5].perms = EMUL_PERM_R;
  102. regs[5].value = 0x5;
  103. regs[8].access_mask = 0x81;
  104. regs[8].perms = EMUL_PERM_RW;
  105. regs[0x40].access_mask = 0x7F;
  106. regs[0x40].perms = EMUL_PERM_RW;
  107. regs[0x41].access_mask = 7;
  108. regs[0x41].perms = EMUL_PERM_RW;
  109. regs[0x42].access_mask = 7;
  110. regs[0x42].perms = EMUL_PERM_RW;
  111. regs[0x42].value = 0x4;
  112. regs[0x45].access_mask = 0x3F;
  113. regs[0x45].perms = EMUL_PERM_RW;
  114. regs[0x45].value = 0x1;
  115. regs[0x46].access_mask = 0x80;
  116. regs[0x46].perms = EMUL_PERM_RW;
  117. regs[0x46].value = 0x80;
  118. }
  119. return 0;
  120. }
  121. static const struct udevice_id sandbox_spmi_ids[] = {
  122. { .compatible = "sandbox,spmi" },
  123. { }
  124. };
  125. U_BOOT_DRIVER(msm_spmi) = {
  126. .name = "sandbox_spmi",
  127. .id = UCLASS_SPMI,
  128. .of_match = sandbox_spmi_ids,
  129. .ops = &sandbox_spmi_ops,
  130. .probe = sandbox_spmi_probe,
  131. .priv_auto = sizeof(struct sandbox_spmi_priv),
  132. };