2
0

i2c-echo.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /*
  2. * Example I2C device using asynchronous I2C send.
  3. *
  4. * Copyright (C) 2023 Samsung Electronics Co., Ltd. All Rights Reserved.
  5. *
  6. * This work is licensed under the terms of the GNU GPL, version 2. See
  7. * the COPYING file in the top-level directory.
  8. *
  9. */
  10. #include "qemu/osdep.h"
  11. #include "qemu/timer.h"
  12. #include "qemu/main-loop.h"
  13. #include "block/aio.h"
  14. #include "hw/i2c/i2c.h"
  15. #include "trace.h"
  16. #define TYPE_I2C_ECHO "i2c-echo"
  17. OBJECT_DECLARE_SIMPLE_TYPE(I2CEchoState, I2C_ECHO)
  18. enum i2c_echo_state {
  19. I2C_ECHO_STATE_IDLE,
  20. I2C_ECHO_STATE_START_SEND,
  21. I2C_ECHO_STATE_ACK,
  22. };
  23. typedef struct I2CEchoState {
  24. I2CSlave parent_obj;
  25. I2CBus *bus;
  26. enum i2c_echo_state state;
  27. QEMUBH *bh;
  28. unsigned int pos;
  29. uint8_t data[3];
  30. } I2CEchoState;
  31. static void i2c_echo_bh(void *opaque)
  32. {
  33. I2CEchoState *state = opaque;
  34. switch (state->state) {
  35. case I2C_ECHO_STATE_IDLE:
  36. return;
  37. case I2C_ECHO_STATE_START_SEND:
  38. if (i2c_start_send_async(state->bus, state->data[0])) {
  39. goto release_bus;
  40. }
  41. state->pos++;
  42. state->state = I2C_ECHO_STATE_ACK;
  43. return;
  44. case I2C_ECHO_STATE_ACK:
  45. if (state->pos > 2) {
  46. break;
  47. }
  48. if (i2c_send_async(state->bus, state->data[state->pos++])) {
  49. break;
  50. }
  51. return;
  52. }
  53. i2c_end_transfer(state->bus);
  54. release_bus:
  55. i2c_bus_release(state->bus);
  56. state->state = I2C_ECHO_STATE_IDLE;
  57. }
  58. static int i2c_echo_event(I2CSlave *s, enum i2c_event event)
  59. {
  60. I2CEchoState *state = I2C_ECHO(s);
  61. switch (event) {
  62. case I2C_START_RECV:
  63. state->pos = 0;
  64. trace_i2c_echo_event(DEVICE(s)->canonical_path, "I2C_START_RECV");
  65. break;
  66. case I2C_START_SEND:
  67. state->pos = 0;
  68. trace_i2c_echo_event(DEVICE(s)->canonical_path, "I2C_START_SEND");
  69. break;
  70. case I2C_FINISH:
  71. state->pos = 0;
  72. state->state = I2C_ECHO_STATE_START_SEND;
  73. i2c_bus_master(state->bus, state->bh);
  74. trace_i2c_echo_event(DEVICE(s)->canonical_path, "I2C_FINISH");
  75. break;
  76. case I2C_NACK:
  77. trace_i2c_echo_event(DEVICE(s)->canonical_path, "I2C_NACK");
  78. break;
  79. default:
  80. trace_i2c_echo_event(DEVICE(s)->canonical_path, "UNHANDLED");
  81. return -1;
  82. }
  83. return 0;
  84. }
  85. static uint8_t i2c_echo_recv(I2CSlave *s)
  86. {
  87. I2CEchoState *state = I2C_ECHO(s);
  88. if (state->pos > 2) {
  89. return 0xff;
  90. }
  91. trace_i2c_echo_recv(DEVICE(s)->canonical_path, state->data[state->pos]);
  92. return state->data[state->pos++];
  93. }
  94. static int i2c_echo_send(I2CSlave *s, uint8_t data)
  95. {
  96. I2CEchoState *state = I2C_ECHO(s);
  97. trace_i2c_echo_send(DEVICE(s)->canonical_path, data);
  98. if (state->pos > 2) {
  99. return -1;
  100. }
  101. state->data[state->pos++] = data;
  102. return 0;
  103. }
  104. static void i2c_echo_realize(DeviceState *dev, Error **errp)
  105. {
  106. I2CEchoState *state = I2C_ECHO(dev);
  107. BusState *bus = qdev_get_parent_bus(dev);
  108. state->bus = I2C_BUS(bus);
  109. state->bh = qemu_bh_new(i2c_echo_bh, state);
  110. return;
  111. }
  112. static void i2c_echo_class_init(ObjectClass *oc, void *data)
  113. {
  114. I2CSlaveClass *sc = I2C_SLAVE_CLASS(oc);
  115. DeviceClass *dc = DEVICE_CLASS(oc);
  116. dc->realize = i2c_echo_realize;
  117. sc->event = i2c_echo_event;
  118. sc->recv = i2c_echo_recv;
  119. sc->send = i2c_echo_send;
  120. }
  121. static const TypeInfo i2c_echo = {
  122. .name = TYPE_I2C_ECHO,
  123. .parent = TYPE_I2C_SLAVE,
  124. .instance_size = sizeof(I2CEchoState),
  125. .class_init = i2c_echo_class_init,
  126. };
  127. static void register_types(void)
  128. {
  129. type_register_static(&i2c_echo);
  130. }
  131. type_init(register_types);