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. */
smbus_quick_command(I2CBus * bus,uint8_t addr,int read)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
smbus_receive_byte(I2CBus * bus,uint8_t addr)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
smbus_send_byte(I2CBus * bus,uint8_t addr,uint8_t data)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
smbus_read_byte(I2CBus * bus,uint8_t addr,uint8_t command)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
smbus_write_byte(I2CBus * bus,uint8_t addr,uint8_t command,uint8_t data)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
smbus_read_word(I2CBus * bus,uint8_t addr,uint8_t command)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
smbus_write_word(I2CBus * bus,uint8_t addr,uint8_t command,uint16_t data)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
smbus_read_block(I2CBus * bus,uint8_t addr,uint8_t command,uint8_t * data,int len,bool recv_len,bool send_cmd)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
smbus_write_block(I2CBus * bus,uint8_t addr,uint8_t command,uint8_t * data,int len,bool send_len)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