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