1 /* 2 * QEMU SMBus host (master) emulation. 3 * 4 * This code emulates SMBus transactions from the master point of view, 5 * it runs the individual I2C transaction to do the SMBus protocol 6 * over I2C. 7 * 8 * Copyright (c) 2007 CodeSourcery. 9 * Written by Paul Brook 10 * 11 * This code is licensed under the LGPL. 12 */ 13 14 #include "qemu/osdep.h" 15 #include "hw/i2c/i2c.h" 16 #include "hw/i2c/smbus_master.h" 17 18 /* Master device commands. */ 19 int smbus_quick_command(I2CBus *bus, uint8_t addr, int read) 20 { 21 if (i2c_start_transfer(bus, addr, read)) { 22 return -1; 23 } 24 i2c_end_transfer(bus); 25 return 0; 26 } 27 28 int smbus_receive_byte(I2CBus *bus, uint8_t addr) 29 { 30 uint8_t data; 31 32 if (i2c_start_recv(bus, addr)) { 33 return -1; 34 } 35 data = i2c_recv(bus); 36 i2c_nack(bus); 37 i2c_end_transfer(bus); 38 return data; 39 } 40 41 int smbus_send_byte(I2CBus *bus, uint8_t addr, uint8_t data) 42 { 43 if (i2c_start_send(bus, addr)) { 44 return -1; 45 } 46 i2c_send(bus, data); 47 i2c_end_transfer(bus); 48 return 0; 49 } 50 51 int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command) 52 { 53 uint8_t data; 54 if (i2c_start_send(bus, addr)) { 55 return -1; 56 } 57 i2c_send(bus, command); 58 if (i2c_start_recv(bus, addr)) { 59 i2c_end_transfer(bus); 60 return -1; 61 } 62 data = i2c_recv(bus); 63 i2c_nack(bus); 64 i2c_end_transfer(bus); 65 return data; 66 } 67 68 int smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data) 69 { 70 if (i2c_start_send(bus, addr)) { 71 return -1; 72 } 73 i2c_send(bus, command); 74 i2c_send(bus, data); 75 i2c_end_transfer(bus); 76 return 0; 77 } 78 79 int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command) 80 { 81 uint16_t data; 82 if (i2c_start_send(bus, addr)) { 83 return -1; 84 } 85 i2c_send(bus, command); 86 if (i2c_start_recv(bus, addr)) { 87 i2c_end_transfer(bus); 88 return -1; 89 } 90 data = i2c_recv(bus); 91 data |= i2c_recv(bus) << 8; 92 i2c_nack(bus); 93 i2c_end_transfer(bus); 94 return data; 95 } 96 97 int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data) 98 { 99 if (i2c_start_send(bus, addr)) { 100 return -1; 101 } 102 i2c_send(bus, command); 103 i2c_send(bus, data & 0xff); 104 i2c_send(bus, data >> 8); 105 i2c_end_transfer(bus); 106 return 0; 107 } 108 109 int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, 110 int len, bool recv_len, bool send_cmd) 111 { 112 int rlen; 113 int i; 114 115 if (send_cmd) { 116 if (i2c_start_send(bus, addr)) { 117 return -1; 118 } 119 i2c_send(bus, command); 120 } 121 if (i2c_start_recv(bus, addr)) { 122 if (send_cmd) { 123 i2c_end_transfer(bus); 124 } 125 return -1; 126 } 127 if (recv_len) { 128 rlen = i2c_recv(bus); 129 } else { 130 rlen = len; 131 } 132 if (rlen > len) { 133 rlen = 0; 134 } 135 for (i = 0; i < rlen; i++) { 136 data[i] = i2c_recv(bus); 137 } 138 i2c_nack(bus); 139 i2c_end_transfer(bus); 140 return rlen; 141 } 142 143 int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, 144 int len, bool send_len) 145 { 146 int i; 147 148 if (len > 32) { 149 len = 32; 150 } 151 152 if (i2c_start_send(bus, addr)) { 153 return -1; 154 } 155 i2c_send(bus, command); 156 if (send_len) { 157 i2c_send(bus, len); 158 } 159 for (i = 0; i < len; i++) { 160 i2c_send(bus, data[i]); 161 } 162 i2c_end_transfer(bus); 163 return 0; 164 } 165