smbus_master.c (3437B)
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. */ 19int 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 28int 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 41int 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 51int 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 68int 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 79int 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 97int 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 109int 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 143int 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}