xref: /openbmc/qemu/hw/i2c/smbus_master.c (revision 9516034d05a8c71ef157a59f525e4c4f7ed79827)
193198b6cSCorey Minyard /*
293198b6cSCorey Minyard  * QEMU SMBus host (master) emulation.
393198b6cSCorey Minyard  *
493198b6cSCorey Minyard  * This code emulates SMBus transactions from the master point of view,
593198b6cSCorey Minyard  * it runs the individual I2C transaction to do the SMBus protocol
693198b6cSCorey Minyard  * over I2C.
793198b6cSCorey Minyard  *
893198b6cSCorey Minyard  * Copyright (c) 2007 CodeSourcery.
993198b6cSCorey Minyard  * Written by Paul Brook
1093198b6cSCorey Minyard  *
1193198b6cSCorey Minyard  * This code is licensed under the LGPL.
1293198b6cSCorey Minyard  */
1393198b6cSCorey Minyard 
1493198b6cSCorey Minyard #include "qemu/osdep.h"
1593198b6cSCorey Minyard #include "hw/i2c/i2c.h"
1693198b6cSCorey Minyard #include "hw/i2c/smbus_master.h"
1793198b6cSCorey Minyard 
1893198b6cSCorey Minyard /* Master device commands.  */
smbus_quick_command(I2CBus * bus,uint8_t addr,int read)1993198b6cSCorey Minyard int smbus_quick_command(I2CBus *bus, uint8_t addr, int read)
2093198b6cSCorey Minyard {
2193198b6cSCorey Minyard     if (i2c_start_transfer(bus, addr, read)) {
2293198b6cSCorey Minyard         return -1;
2393198b6cSCorey Minyard     }
2493198b6cSCorey Minyard     i2c_end_transfer(bus);
2593198b6cSCorey Minyard     return 0;
2693198b6cSCorey Minyard }
2793198b6cSCorey Minyard 
smbus_receive_byte(I2CBus * bus,uint8_t addr)2893198b6cSCorey Minyard int smbus_receive_byte(I2CBus *bus, uint8_t addr)
2993198b6cSCorey Minyard {
3093198b6cSCorey Minyard     uint8_t data;
3193198b6cSCorey Minyard 
32*90603c5bSPhilippe Mathieu-Daudé     if (i2c_start_recv(bus, addr)) {
3393198b6cSCorey Minyard         return -1;
3493198b6cSCorey Minyard     }
3593198b6cSCorey Minyard     data = i2c_recv(bus);
3693198b6cSCorey Minyard     i2c_nack(bus);
3793198b6cSCorey Minyard     i2c_end_transfer(bus);
3893198b6cSCorey Minyard     return data;
3993198b6cSCorey Minyard }
4093198b6cSCorey Minyard 
smbus_send_byte(I2CBus * bus,uint8_t addr,uint8_t data)4193198b6cSCorey Minyard int smbus_send_byte(I2CBus *bus, uint8_t addr, uint8_t data)
4293198b6cSCorey Minyard {
43*90603c5bSPhilippe Mathieu-Daudé     if (i2c_start_send(bus, addr)) {
4493198b6cSCorey Minyard         return -1;
4593198b6cSCorey Minyard     }
4693198b6cSCorey Minyard     i2c_send(bus, data);
4793198b6cSCorey Minyard     i2c_end_transfer(bus);
4893198b6cSCorey Minyard     return 0;
4993198b6cSCorey Minyard }
5093198b6cSCorey Minyard 
smbus_read_byte(I2CBus * bus,uint8_t addr,uint8_t command)5193198b6cSCorey Minyard int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command)
5293198b6cSCorey Minyard {
5393198b6cSCorey Minyard     uint8_t data;
54*90603c5bSPhilippe Mathieu-Daudé     if (i2c_start_send(bus, addr)) {
5593198b6cSCorey Minyard         return -1;
5693198b6cSCorey Minyard     }
5793198b6cSCorey Minyard     i2c_send(bus, command);
58*90603c5bSPhilippe Mathieu-Daudé     if (i2c_start_recv(bus, addr)) {
5993198b6cSCorey Minyard         i2c_end_transfer(bus);
6093198b6cSCorey Minyard         return -1;
6193198b6cSCorey Minyard     }
6293198b6cSCorey Minyard     data = i2c_recv(bus);
6393198b6cSCorey Minyard     i2c_nack(bus);
6493198b6cSCorey Minyard     i2c_end_transfer(bus);
6593198b6cSCorey Minyard     return data;
6693198b6cSCorey Minyard }
6793198b6cSCorey Minyard 
smbus_write_byte(I2CBus * bus,uint8_t addr,uint8_t command,uint8_t data)6893198b6cSCorey Minyard int smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data)
6993198b6cSCorey Minyard {
70*90603c5bSPhilippe Mathieu-Daudé     if (i2c_start_send(bus, addr)) {
7193198b6cSCorey Minyard         return -1;
7293198b6cSCorey Minyard     }
7393198b6cSCorey Minyard     i2c_send(bus, command);
7493198b6cSCorey Minyard     i2c_send(bus, data);
7593198b6cSCorey Minyard     i2c_end_transfer(bus);
7693198b6cSCorey Minyard     return 0;
7793198b6cSCorey Minyard }
7893198b6cSCorey Minyard 
smbus_read_word(I2CBus * bus,uint8_t addr,uint8_t command)7993198b6cSCorey Minyard int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command)
8093198b6cSCorey Minyard {
8193198b6cSCorey Minyard     uint16_t data;
82*90603c5bSPhilippe Mathieu-Daudé     if (i2c_start_send(bus, addr)) {
8393198b6cSCorey Minyard         return -1;
8493198b6cSCorey Minyard     }
8593198b6cSCorey Minyard     i2c_send(bus, command);
86*90603c5bSPhilippe Mathieu-Daudé     if (i2c_start_recv(bus, addr)) {
8793198b6cSCorey Minyard         i2c_end_transfer(bus);
8893198b6cSCorey Minyard         return -1;
8993198b6cSCorey Minyard     }
9093198b6cSCorey Minyard     data = i2c_recv(bus);
9193198b6cSCorey Minyard     data |= i2c_recv(bus) << 8;
9293198b6cSCorey Minyard     i2c_nack(bus);
9393198b6cSCorey Minyard     i2c_end_transfer(bus);
9493198b6cSCorey Minyard     return data;
9593198b6cSCorey Minyard }
9693198b6cSCorey Minyard 
smbus_write_word(I2CBus * bus,uint8_t addr,uint8_t command,uint16_t data)9793198b6cSCorey Minyard int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data)
9893198b6cSCorey Minyard {
99*90603c5bSPhilippe Mathieu-Daudé     if (i2c_start_send(bus, addr)) {
10093198b6cSCorey Minyard         return -1;
10193198b6cSCorey Minyard     }
10293198b6cSCorey Minyard     i2c_send(bus, command);
10393198b6cSCorey Minyard     i2c_send(bus, data & 0xff);
10493198b6cSCorey Minyard     i2c_send(bus, data >> 8);
10593198b6cSCorey Minyard     i2c_end_transfer(bus);
10693198b6cSCorey Minyard     return 0;
10793198b6cSCorey Minyard }
10893198b6cSCorey Minyard 
smbus_read_block(I2CBus * bus,uint8_t addr,uint8_t command,uint8_t * data,int len,bool recv_len,bool send_cmd)10993198b6cSCorey Minyard int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
11093198b6cSCorey Minyard                      int len, bool recv_len, bool send_cmd)
11193198b6cSCorey Minyard {
11293198b6cSCorey Minyard     int rlen;
11393198b6cSCorey Minyard     int i;
11493198b6cSCorey Minyard 
11593198b6cSCorey Minyard     if (send_cmd) {
116*90603c5bSPhilippe Mathieu-Daudé         if (i2c_start_send(bus, addr)) {
11793198b6cSCorey Minyard             return -1;
11893198b6cSCorey Minyard         }
11993198b6cSCorey Minyard         i2c_send(bus, command);
12093198b6cSCorey Minyard     }
121*90603c5bSPhilippe Mathieu-Daudé     if (i2c_start_recv(bus, addr)) {
12293198b6cSCorey Minyard         if (send_cmd) {
12393198b6cSCorey Minyard             i2c_end_transfer(bus);
12493198b6cSCorey Minyard         }
12593198b6cSCorey Minyard         return -1;
12693198b6cSCorey Minyard     }
12793198b6cSCorey Minyard     if (recv_len) {
12893198b6cSCorey Minyard         rlen = i2c_recv(bus);
12993198b6cSCorey Minyard     } else {
13093198b6cSCorey Minyard         rlen = len;
13193198b6cSCorey Minyard     }
13293198b6cSCorey Minyard     if (rlen > len) {
13393198b6cSCorey Minyard         rlen = 0;
13493198b6cSCorey Minyard     }
13593198b6cSCorey Minyard     for (i = 0; i < rlen; i++) {
13693198b6cSCorey Minyard         data[i] = i2c_recv(bus);
13793198b6cSCorey Minyard     }
13893198b6cSCorey Minyard     i2c_nack(bus);
13993198b6cSCorey Minyard     i2c_end_transfer(bus);
14093198b6cSCorey Minyard     return rlen;
14193198b6cSCorey Minyard }
14293198b6cSCorey Minyard 
smbus_write_block(I2CBus * bus,uint8_t addr,uint8_t command,uint8_t * data,int len,bool send_len)14393198b6cSCorey Minyard int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
14493198b6cSCorey Minyard                       int len, bool send_len)
14593198b6cSCorey Minyard {
14693198b6cSCorey Minyard     int i;
14793198b6cSCorey Minyard 
14893198b6cSCorey Minyard     if (len > 32) {
14993198b6cSCorey Minyard         len = 32;
15093198b6cSCorey Minyard     }
15193198b6cSCorey Minyard 
152*90603c5bSPhilippe Mathieu-Daudé     if (i2c_start_send(bus, addr)) {
15393198b6cSCorey Minyard         return -1;
15493198b6cSCorey Minyard     }
15593198b6cSCorey Minyard     i2c_send(bus, command);
15693198b6cSCorey Minyard     if (send_len) {
15793198b6cSCorey Minyard         i2c_send(bus, len);
15893198b6cSCorey Minyard     }
15993198b6cSCorey Minyard     for (i = 0; i < len; i++) {
16093198b6cSCorey Minyard         i2c_send(bus, data[i]);
16193198b6cSCorey Minyard     }
16293198b6cSCorey Minyard     i2c_end_transfer(bus);
16393198b6cSCorey Minyard     return 0;
16493198b6cSCorey Minyard }
165