symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/smbus.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * QEMU SMBus device emulation.
       
     3  *
       
     4  * Copyright (c) 2007 CodeSourcery.
       
     5  * Written by Paul Brook
       
     6  *
       
     7  * This code is licenced under the LGPL.
       
     8  */
       
     9 
       
    10 /* TODO: Implement PEC.  */
       
    11 
       
    12 #include "hw.h"
       
    13 #include "i2c.h"
       
    14 #include "smbus.h"
       
    15 
       
    16 //#define DEBUG_SMBUS 1
       
    17 
       
    18 #ifdef DEBUG_SMBUS
       
    19 #define DPRINTF(fmt, args...) \
       
    20 do { printf("smbus(%02x): " fmt , dev->i2c.address, ##args); } while (0)
       
    21 #define BADF(fmt, args...) \
       
    22 do { fprintf(stderr, "smbus: error: " fmt , ##args); exit(1);} while (0)
       
    23 #else
       
    24 #define DPRINTF(fmt, args...) do {} while(0)
       
    25 #define BADF(fmt, args...) \
       
    26 do { fprintf(stderr, "smbus: error: " fmt , ##args);} while (0)
       
    27 #endif
       
    28 
       
    29 enum {
       
    30     SMBUS_IDLE,
       
    31     SMBUS_WRITE_DATA,
       
    32     SMBUS_RECV_BYTE,
       
    33     SMBUS_READ_DATA,
       
    34     SMBUS_DONE,
       
    35     SMBUS_CONFUSED = -1
       
    36 };
       
    37 
       
    38 static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
       
    39 {
       
    40     DPRINTF("Quick Command %d\n", recv);
       
    41     if (dev->quick_cmd)
       
    42         dev->quick_cmd(dev, recv);
       
    43 }
       
    44 
       
    45 static void smbus_do_write(SMBusDevice *dev)
       
    46 {
       
    47     if (dev->data_len == 0) {
       
    48         smbus_do_quick_cmd(dev, 0);
       
    49     } else if (dev->data_len == 1) {
       
    50         DPRINTF("Send Byte\n");
       
    51         if (dev->send_byte) {
       
    52             dev->send_byte(dev, dev->data_buf[0]);
       
    53         }
       
    54     } else {
       
    55         dev->command = dev->data_buf[0];
       
    56         DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1);
       
    57         if (dev->write_data) {
       
    58             dev->write_data(dev, dev->command, dev->data_buf + 1,
       
    59                             dev->data_len - 1);
       
    60         }
       
    61     }
       
    62 }
       
    63 
       
    64 static void smbus_i2c_event(i2c_slave *s, enum i2c_event event)
       
    65 {
       
    66     SMBusDevice *dev = (SMBusDevice *)s;
       
    67     switch (event) {
       
    68     case I2C_START_SEND:
       
    69         switch (dev->mode) {
       
    70         case SMBUS_IDLE:
       
    71             DPRINTF("Incoming data\n");
       
    72             dev->mode = SMBUS_WRITE_DATA;
       
    73             break;
       
    74         default:
       
    75             BADF("Unexpected send start condition in state %d\n", dev->mode);
       
    76             dev->mode = SMBUS_CONFUSED;
       
    77             break;
       
    78         }
       
    79         break;
       
    80 
       
    81     case I2C_START_RECV:
       
    82         switch (dev->mode) {
       
    83         case SMBUS_IDLE:
       
    84             DPRINTF("Read mode\n");
       
    85             dev->mode = SMBUS_RECV_BYTE;
       
    86             break;
       
    87         case SMBUS_WRITE_DATA:
       
    88             if (dev->data_len == 0) {
       
    89                 BADF("Read after write with no data\n");
       
    90                 dev->mode = SMBUS_CONFUSED;
       
    91             } else {
       
    92                 if (dev->data_len > 1) {
       
    93                     smbus_do_write(dev);
       
    94                 } else {
       
    95                     dev->command = dev->data_buf[0];
       
    96                     DPRINTF("%02x: Command %d\n", dev->i2c.address,
       
    97                             dev->command);
       
    98                 }
       
    99                 DPRINTF("Read mode\n");
       
   100                 dev->data_len = 0;
       
   101                 dev->mode = SMBUS_READ_DATA;
       
   102             }
       
   103             break;
       
   104         default:
       
   105             BADF("Unexpected recv start condition in state %d\n", dev->mode);
       
   106             dev->mode = SMBUS_CONFUSED;
       
   107             break;
       
   108         }
       
   109         break;
       
   110 
       
   111     case I2C_FINISH:
       
   112         switch (dev->mode) {
       
   113         case SMBUS_WRITE_DATA:
       
   114             smbus_do_write(dev);
       
   115             break;
       
   116         case SMBUS_RECV_BYTE:
       
   117             smbus_do_quick_cmd(dev, 1);
       
   118             break;
       
   119         case SMBUS_READ_DATA:
       
   120             BADF("Unexpected stop during receive\n");
       
   121             break;
       
   122         default:
       
   123             /* Nothing to do.  */
       
   124             break;
       
   125         }
       
   126         dev->mode = SMBUS_IDLE;
       
   127         dev->data_len = 0;
       
   128         break;
       
   129 
       
   130     case I2C_NACK:
       
   131         switch (dev->mode) {
       
   132         case SMBUS_DONE:
       
   133             /* Nothing to do.  */
       
   134             break;
       
   135         case SMBUS_READ_DATA:
       
   136             dev->mode = SMBUS_DONE;
       
   137             break;
       
   138         default:
       
   139             BADF("Unexpected NACK in state %d\n", dev->mode);
       
   140             dev->mode = SMBUS_CONFUSED;
       
   141             break;
       
   142         }
       
   143     }
       
   144 }
       
   145 
       
   146 static int smbus_i2c_recv(i2c_slave *s)
       
   147 {
       
   148     SMBusDevice *dev = (SMBusDevice *)s;
       
   149     int ret;
       
   150 
       
   151     switch (dev->mode) {
       
   152     case SMBUS_RECV_BYTE:
       
   153         if (dev->receive_byte) {
       
   154             ret = dev->receive_byte(dev);
       
   155         } else {
       
   156             ret = 0;
       
   157         }
       
   158         DPRINTF("Receive Byte %02x\n", ret);
       
   159         dev->mode = SMBUS_DONE;
       
   160         break;
       
   161     case SMBUS_READ_DATA:
       
   162         if (dev->read_data) {
       
   163             ret = dev->read_data(dev, dev->command, dev->data_len);
       
   164             dev->data_len++;
       
   165         } else {
       
   166             ret = 0;
       
   167         }
       
   168         DPRINTF("Read data %02x\n", ret);
       
   169         break;
       
   170     default:
       
   171         BADF("Unexpected read in state %d\n", dev->mode);
       
   172         dev->mode = SMBUS_CONFUSED;
       
   173         ret = 0;
       
   174         break;
       
   175     }
       
   176     return ret;
       
   177 }
       
   178 
       
   179 static int smbus_i2c_send(i2c_slave *s, uint8_t data)
       
   180 {
       
   181     SMBusDevice *dev = (SMBusDevice *)s;
       
   182     switch (dev->mode) {
       
   183     case SMBUS_WRITE_DATA:
       
   184         DPRINTF("Write data %02x\n", data);
       
   185         dev->data_buf[dev->data_len++] = data;
       
   186         break;
       
   187     default:
       
   188         BADF("Unexpected write in state %d\n", dev->mode);
       
   189         break;
       
   190     }
       
   191     return 0;
       
   192 }
       
   193 
       
   194 SMBusDevice *smbus_device_init(i2c_bus *bus, int address, int size)
       
   195 {
       
   196     SMBusDevice *dev;
       
   197 
       
   198     if (size < sizeof(SMBusDevice))
       
   199         hw_error("SMBus struct too small");
       
   200 
       
   201     dev = (SMBusDevice *)i2c_slave_init(bus, address, size);
       
   202     dev->i2c.event = smbus_i2c_event;
       
   203     dev->i2c.recv = smbus_i2c_recv;
       
   204     dev->i2c.send = smbus_i2c_send;
       
   205 
       
   206     return dev;
       
   207 }
       
   208 
       
   209 /* Master device commands.  */
       
   210 void smbus_quick_command(i2c_bus *bus, int addr, int read)
       
   211 {
       
   212     i2c_start_transfer(bus, addr, read);
       
   213     i2c_end_transfer(bus);
       
   214 }
       
   215 
       
   216 uint8_t smbus_receive_byte(i2c_bus *bus, int addr)
       
   217 {
       
   218     uint8_t data;
       
   219 
       
   220     i2c_start_transfer(bus, addr, 1);
       
   221     data = i2c_recv(bus);
       
   222     i2c_nack(bus);
       
   223     i2c_end_transfer(bus);
       
   224     return data;
       
   225 }
       
   226 
       
   227 void smbus_send_byte(i2c_bus *bus, int addr, uint8_t data)
       
   228 {
       
   229     i2c_start_transfer(bus, addr, 0);
       
   230     i2c_send(bus, data);
       
   231     i2c_end_transfer(bus);
       
   232 }
       
   233 
       
   234 uint8_t smbus_read_byte(i2c_bus *bus, int addr, uint8_t command)
       
   235 {
       
   236     uint8_t data;
       
   237     i2c_start_transfer(bus, addr, 0);
       
   238     i2c_send(bus, command);
       
   239     i2c_start_transfer(bus, addr, 1);
       
   240     data = i2c_recv(bus);
       
   241     i2c_nack(bus);
       
   242     i2c_end_transfer(bus);
       
   243     return data;
       
   244 }
       
   245 
       
   246 void smbus_write_byte(i2c_bus *bus, int addr, uint8_t command, uint8_t data)
       
   247 {
       
   248     i2c_start_transfer(bus, addr, 0);
       
   249     i2c_send(bus, command);
       
   250     i2c_send(bus, data);
       
   251     i2c_end_transfer(bus);
       
   252 }
       
   253 
       
   254 uint16_t smbus_read_word(i2c_bus *bus, int addr, uint8_t command)
       
   255 {
       
   256     uint16_t data;
       
   257     i2c_start_transfer(bus, addr, 0);
       
   258     i2c_send(bus, command);
       
   259     i2c_start_transfer(bus, addr, 1);
       
   260     data = i2c_recv(bus);
       
   261     data |= i2c_recv(bus) << 8;
       
   262     i2c_nack(bus);
       
   263     i2c_end_transfer(bus);
       
   264     return data;
       
   265 }
       
   266 
       
   267 void smbus_write_word(i2c_bus *bus, int addr, uint8_t command, uint16_t data)
       
   268 {
       
   269     i2c_start_transfer(bus, addr, 0);
       
   270     i2c_send(bus, command);
       
   271     i2c_send(bus, data & 0xff);
       
   272     i2c_send(bus, data >> 8);
       
   273     i2c_end_transfer(bus);
       
   274 }
       
   275 
       
   276 int smbus_read_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data)
       
   277 {
       
   278     int len;
       
   279     int i;
       
   280 
       
   281     i2c_start_transfer(bus, addr, 0);
       
   282     i2c_send(bus, command);
       
   283     i2c_start_transfer(bus, addr, 1);
       
   284     len = i2c_recv(bus);
       
   285     if (len > 32)
       
   286         len = 0;
       
   287     for (i = 0; i < len; i++)
       
   288         data[i] = i2c_recv(bus);
       
   289     i2c_nack(bus);
       
   290     i2c_end_transfer(bus);
       
   291     return len;
       
   292 }
       
   293 
       
   294 void smbus_write_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data,
       
   295                        int len)
       
   296 {
       
   297     int i;
       
   298 
       
   299     if (len > 32)
       
   300         len = 32;
       
   301 
       
   302     i2c_start_transfer(bus, addr, 0);
       
   303     i2c_send(bus, command);
       
   304     i2c_send(bus, len);
       
   305     for (i = 0; i < len; i++)
       
   306         i2c_send(bus, data[i]);
       
   307     i2c_end_transfer(bus);
       
   308 }