spmi-sandbox.c 3.7 KB

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