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_transfer(bus, addr, 1)) {
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_transfer(bus, addr, 0)) {
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_transfer(bus, addr, 0)) {
55 return -1;
56 }
57 i2c_send(bus, command);
58 if (i2c_start_transfer(bus, addr, 1)) {
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_transfer(bus, addr, 0)) {
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_transfer(bus, addr, 0)) {
83 return -1;
84 }
85 i2c_send(bus, command);
86 if (i2c_start_transfer(bus, addr, 1)) {
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_transfer(bus, addr, 0)) {
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_transfer(bus, addr, 0)) {
117 return -1;
118 }
119 i2c_send(bus, command);
120 }
121 if (i2c_start_transfer(bus, addr, 1)) {
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_transfer(bus, addr, 0)) {
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