pca9552.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. * PCA9552 I2C LED blinker
  3. *
  4. * https://www.nxp.com/docs/en/application-note/AN264.pdf
  5. *
  6. * Copyright (c) 2017-2018, IBM Corporation.
  7. *
  8. * This work is licensed under the terms of the GNU GPL, version 2 or
  9. * later. See the COPYING file in the top-level directory.
  10. */
  11. #include "qemu/osdep.h"
  12. #include "qemu/log.h"
  13. #include "qemu/module.h"
  14. #include "hw/misc/pca9552.h"
  15. #include "hw/misc/pca9552_regs.h"
  16. #include "migration/vmstate.h"
  17. #define PCA9552_LED_ON 0x0
  18. #define PCA9552_LED_OFF 0x1
  19. #define PCA9552_LED_PWM0 0x2
  20. #define PCA9552_LED_PWM1 0x3
  21. static uint8_t pca9552_pin_get_config(PCA9552State *s, int pin)
  22. {
  23. uint8_t reg = PCA9552_LS0 + (pin / 4);
  24. uint8_t shift = (pin % 4) << 1;
  25. return extract32(s->regs[reg], shift, 2);
  26. }
  27. static void pca9552_update_pin_input(PCA9552State *s)
  28. {
  29. int i;
  30. for (i = 0; i < s->nr_leds; i++) {
  31. uint8_t input_reg = PCA9552_INPUT0 + (i / 8);
  32. uint8_t input_shift = (i % 8);
  33. uint8_t config = pca9552_pin_get_config(s, i);
  34. switch (config) {
  35. case PCA9552_LED_ON:
  36. s->regs[input_reg] |= 1 << input_shift;
  37. break;
  38. case PCA9552_LED_OFF:
  39. s->regs[input_reg] &= ~(1 << input_shift);
  40. break;
  41. case PCA9552_LED_PWM0:
  42. case PCA9552_LED_PWM1:
  43. /* TODO */
  44. default:
  45. break;
  46. }
  47. }
  48. }
  49. static uint8_t pca9552_read(PCA9552State *s, uint8_t reg)
  50. {
  51. switch (reg) {
  52. case PCA9552_INPUT0:
  53. case PCA9552_INPUT1:
  54. case PCA9552_PSC0:
  55. case PCA9552_PWM0:
  56. case PCA9552_PSC1:
  57. case PCA9552_PWM1:
  58. case PCA9552_LS0:
  59. case PCA9552_LS1:
  60. case PCA9552_LS2:
  61. case PCA9552_LS3:
  62. return s->regs[reg];
  63. default:
  64. qemu_log_mask(LOG_GUEST_ERROR, "%s: unexpected read to register %d\n",
  65. __func__, reg);
  66. return 0xFF;
  67. }
  68. }
  69. static void pca9552_write(PCA9552State *s, uint8_t reg, uint8_t data)
  70. {
  71. switch (reg) {
  72. case PCA9552_PSC0:
  73. case PCA9552_PWM0:
  74. case PCA9552_PSC1:
  75. case PCA9552_PWM1:
  76. s->regs[reg] = data;
  77. break;
  78. case PCA9552_LS0:
  79. case PCA9552_LS1:
  80. case PCA9552_LS2:
  81. case PCA9552_LS3:
  82. s->regs[reg] = data;
  83. pca9552_update_pin_input(s);
  84. break;
  85. case PCA9552_INPUT0:
  86. case PCA9552_INPUT1:
  87. default:
  88. qemu_log_mask(LOG_GUEST_ERROR, "%s: unexpected write to register %d\n",
  89. __func__, reg);
  90. }
  91. }
  92. /*
  93. * When Auto-Increment is on, the register address is incremented
  94. * after each byte is sent to or received by the device. The index
  95. * rollovers to 0 when the maximum register address is reached.
  96. */
  97. static void pca9552_autoinc(PCA9552State *s)
  98. {
  99. if (s->pointer != 0xFF && s->pointer & PCA9552_AUTOINC) {
  100. uint8_t reg = s->pointer & 0xf;
  101. reg = (reg + 1) % (s->max_reg + 1);
  102. s->pointer = reg | PCA9552_AUTOINC;
  103. }
  104. }
  105. static uint8_t pca9552_recv(I2CSlave *i2c)
  106. {
  107. PCA9552State *s = PCA9552(i2c);
  108. uint8_t ret;
  109. ret = pca9552_read(s, s->pointer & 0xf);
  110. /*
  111. * From the Specs:
  112. *
  113. * Important Note: When a Read sequence is initiated and the
  114. * AI bit is set to Logic Level 1, the Read Sequence MUST
  115. * start by a register different from 0.
  116. *
  117. * I don't know what should be done in this case, so throw an
  118. * error.
  119. */
  120. if (s->pointer == PCA9552_AUTOINC) {
  121. qemu_log_mask(LOG_GUEST_ERROR,
  122. "%s: Autoincrement read starting with register 0\n",
  123. __func__);
  124. }
  125. pca9552_autoinc(s);
  126. return ret;
  127. }
  128. static int pca9552_send(I2CSlave *i2c, uint8_t data)
  129. {
  130. PCA9552State *s = PCA9552(i2c);
  131. /* First byte sent by is the register address */
  132. if (s->len == 0) {
  133. s->pointer = data;
  134. s->len++;
  135. } else {
  136. pca9552_write(s, s->pointer & 0xf, data);
  137. pca9552_autoinc(s);
  138. }
  139. return 0;
  140. }
  141. static int pca9552_event(I2CSlave *i2c, enum i2c_event event)
  142. {
  143. PCA9552State *s = PCA9552(i2c);
  144. s->len = 0;
  145. return 0;
  146. }
  147. static const VMStateDescription pca9552_vmstate = {
  148. .name = "PCA9552",
  149. .version_id = 0,
  150. .minimum_version_id = 0,
  151. .fields = (VMStateField[]) {
  152. VMSTATE_UINT8(len, PCA9552State),
  153. VMSTATE_UINT8(pointer, PCA9552State),
  154. VMSTATE_UINT8_ARRAY(regs, PCA9552State, PCA9552_NR_REGS),
  155. VMSTATE_I2C_SLAVE(i2c, PCA9552State),
  156. VMSTATE_END_OF_LIST()
  157. }
  158. };
  159. static void pca9552_reset(DeviceState *dev)
  160. {
  161. PCA9552State *s = PCA9552(dev);
  162. s->regs[PCA9552_PSC0] = 0xFF;
  163. s->regs[PCA9552_PWM0] = 0x80;
  164. s->regs[PCA9552_PSC1] = 0xFF;
  165. s->regs[PCA9552_PWM1] = 0x80;
  166. s->regs[PCA9552_LS0] = 0x55; /* all OFF */
  167. s->regs[PCA9552_LS1] = 0x55;
  168. s->regs[PCA9552_LS2] = 0x55;
  169. s->regs[PCA9552_LS3] = 0x55;
  170. pca9552_update_pin_input(s);
  171. s->pointer = 0xFF;
  172. s->len = 0;
  173. }
  174. static void pca9552_initfn(Object *obj)
  175. {
  176. PCA9552State *s = PCA9552(obj);
  177. /* If support for the other PCA955X devices are implemented, these
  178. * constant values might be part of class structure describing the
  179. * PCA955X device
  180. */
  181. s->max_reg = PCA9552_LS3;
  182. s->nr_leds = 16;
  183. }
  184. static void pca9552_class_init(ObjectClass *klass, void *data)
  185. {
  186. DeviceClass *dc = DEVICE_CLASS(klass);
  187. I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
  188. k->event = pca9552_event;
  189. k->recv = pca9552_recv;
  190. k->send = pca9552_send;
  191. dc->reset = pca9552_reset;
  192. dc->vmsd = &pca9552_vmstate;
  193. }
  194. static const TypeInfo pca9552_info = {
  195. .name = TYPE_PCA9552,
  196. .parent = TYPE_I2C_SLAVE,
  197. .instance_init = pca9552_initfn,
  198. .instance_size = sizeof(PCA9552State),
  199. .class_init = pca9552_class_init,
  200. };
  201. static void pca9552_register_types(void)
  202. {
  203. type_register_static(&pca9552_info);
  204. }
  205. type_init(pca9552_register_types)