]> git.proxmox.com Git - mirror_qemu.git/blame - hw/i2c/smbus_master.c
Merge remote-tracking branch 'remotes/berrange-gitlab/tags/misc-next-pull-request...
[mirror_qemu.git] / hw / i2c / smbus_master.c
CommitLineData
93198b6c
CM
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"
93198b6c
CM
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
90603c5b 32 if (i2c_start_recv(bus, addr)) {
93198b6c
CM
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{
90603c5b 43 if (i2c_start_send(bus, addr)) {
93198b6c
CM
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;
90603c5b 54 if (i2c_start_send(bus, addr)) {
93198b6c
CM
55 return -1;
56 }
57 i2c_send(bus, command);
90603c5b 58 if (i2c_start_recv(bus, addr)) {
93198b6c
CM
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{
90603c5b 70 if (i2c_start_send(bus, addr)) {
93198b6c
CM
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;
90603c5b 82 if (i2c_start_send(bus, addr)) {
93198b6c
CM
83 return -1;
84 }
85 i2c_send(bus, command);
90603c5b 86 if (i2c_start_recv(bus, addr)) {
93198b6c
CM
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{
90603c5b 99 if (i2c_start_send(bus, addr)) {
93198b6c
CM
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) {
90603c5b 116 if (i2c_start_send(bus, addr)) {
93198b6c
CM
117 return -1;
118 }
119 i2c_send(bus, command);
120 }
90603c5b 121 if (i2c_start_recv(bus, addr)) {
93198b6c
CM
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
90603c5b 152 if (i2c_start_send(bus, addr)) {
93198b6c
CM
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}