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