qemu/hw/i2c/pca9548.c
<<
>>
Prefs
   1/*
   2 * PCA9548 I2C Switch Dummy model
   3 *
   4 * Copyright (c) 2012 Xilinx Inc.
   5 * Copyright (c) 2012 Peter Crosthwaite <peter.crosthwaite@xilinx.com>
   6 *
   7 *  This program is free software; you can redistribute it and/or modify it
   8 *  under the terms of the GNU General Public License as published by the
   9 *  Free Software Foundation; either version 2 of the License, or
  10 *  (at your option) any later version.
  11 *
  12 *  This program is distributed in the hope that it will be useful, but WITHOUT
  13 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14 *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  15 *  for more details.
  16 *
  17 *  You should have received a copy of the GNU General Public License along
  18 *  with this program; if not, see <http://www.gnu.org/licenses/>.
  19 */
  20
  21#include "qemu/osdep.h"
  22#include "hw/i2c/i2c.h"
  23#include "hw/hw.h"
  24#include "sysemu/blockdev.h"
  25#include "hw/i2c/pca9548.h"
  26#include "qemu/log.h"
  27
  28#ifndef PCA9548_DEBUG
  29#define PCA9548_DEBUG 0
  30#endif
  31
  32#define DB_PRINT(fmt, args...) do { \
  33    if (PCA9548_DEBUG) { \
  34        qemu_log("PCA9548: "fmt, ## args); \
  35    } \
  36} while (0);
  37
  38static void pca9548_reset(DeviceState *dev)
  39{
  40    PCA9548State *s = PCA9548(dev);
  41    I2CSlave *i2cs =  I2C_SLAVE(dev);
  42
  43    /* Switch decodes the enitre address range, trample any previously set
  44     * values for address and range
  45     */
  46    i2cs->address = 0;
  47    i2cs->address_range = 0x80;
  48
  49    s->control_reg = 0;
  50}
  51
  52static int pca9548_recv(I2CSlave *i2c)
  53{
  54    PCA9548State *s = PCA9548(i2c);
  55    int i;
  56    int ret = 0;
  57
  58    if (s->control_decoded) {
  59        ret |= s->control_reg;
  60        DB_PRINT("returning control register: %x\n", ret);
  61    } else {
  62        for (i = 0; i < NUM_BUSSES; ++i) {
  63            if (s->control_reg & (1 << i)) {
  64                ret |= i2c_recv(s->busses[i]);
  65                DB_PRINT("recieving from active bus %d:%x\n", i, ret);
  66            }
  67        }
  68    }
  69
  70    return ret;
  71}
  72
  73static int pca9548_send(I2CSlave *i2c, uint8_t data)
  74{
  75    PCA9548State *s = PCA9548(i2c);
  76    int i;
  77    int ret = -1;
  78
  79    if (s->control_decoded) {
  80        DB_PRINT("setting control register: %x\n", data);
  81        s->control_reg = data;
  82        ret = 0;
  83    } else {
  84        for (i = 0; i < NUM_BUSSES; ++i) {
  85            if (s->control_reg & (1 << i)) {
  86                DB_PRINT("sending to active bus %d:%x\n", i, data);
  87                ret &= i2c_send(s->busses[i], data);
  88            }
  89        }
  90    }
  91
  92    return ret;
  93}
  94
  95static void pca9548_event(I2CSlave *i2c, enum i2c_event event)
  96{
  97    PCA9548State *s = PCA9548(i2c);
  98    int i;
  99
 100    s->event = event;
 101    for (i = 0; i < NUM_BUSSES; ++i) {
 102        if (s->control_reg & (1 << i)) {
 103            switch (event) {
 104            /* defer START conditions until we have an address */
 105            case I2C_START_SEND:
 106            case I2C_START_RECV:
 107                break;
 108            /* Forward others to sub busses */
 109            case I2C_FINISH:
 110                if (!s->control_decoded) {
 111                    DB_PRINT("stopping active bus %d\n", i);
 112                    i2c_end_transfer(s->busses[i]);
 113                }
 114                break;
 115            case I2C_NACK:
 116                if (!s->control_decoded) {
 117                    DB_PRINT("nacking active bus %d\n", i);
 118                    i2c_nack(s->busses[i]);
 119                }
 120                break;
 121            }
 122        }
 123    }
 124}
 125
 126static int pca9548_decode_address(I2CSlave *i2c, uint8_t address)
 127{
 128    PCA9548State *s = PCA9548(i2c);
 129    int i;
 130    uint8_t channel_status = 0;
 131
 132    s->control_decoded = address ==
 133                    (PCA9548_CONTROL_ADDR | (s->chip_enable & 0x7));
 134
 135    if (s->control_decoded) {
 136        return 0;
 137    }
 138
 139    for (i = 0; i < NUM_BUSSES; ++i) {
 140        if (s->control_reg & (1 << i)) {
 141            DB_PRINT("starting active bus %d addr:%02x rnw:%d\n", i, address,
 142                    s->event == I2C_START_RECV);
 143            channel_status |= (i2c_start_transfer(s->busses[i], address,
 144                               s->event == I2C_START_RECV)) << i;
 145        }
 146    }
 147
 148    if (s->control_reg == channel_status) {
 149        return 1;
 150    }
 151
 152    return 0;
 153}
 154
 155static void pca9548_init(Object *obj)
 156{
 157    PCA9548State *s = PCA9548(obj);
 158    int i;
 159
 160    for (i = 0; i < NUM_BUSSES; ++i) {
 161        char bus_name[16];
 162
 163        snprintf(bus_name, sizeof(bus_name), "i2c@%d", i);
 164        s->busses[i] = i2c_init_bus(DEVICE(s), bus_name);
 165    }
 166}
 167
 168static void pca9548_realize(DeviceState *dev, Error **errp)
 169{
 170    /* Dummy */
 171}
 172
 173static const VMStateDescription vmstate_PCA9548 = {
 174    .name = "pca9548",
 175    .version_id = 1,
 176    .fields = (VMStateField[]) {
 177        VMSTATE_I2C_SLAVE(i2c, PCA9548State),
 178        VMSTATE_UINT8(control_reg, PCA9548State),
 179        VMSTATE_BOOL(control_decoded, PCA9548State),
 180        VMSTATE_END_OF_LIST()
 181    }
 182};
 183
 184static Property pca9548_properties[] = {
 185    /* These could be GPIOs, but the application is rare, just let machine model
 186     * tie them with props
 187     */
 188    DEFINE_PROP_UINT8("chip-enable", PCA9548State, chip_enable, 0),
 189    DEFINE_PROP_END_OF_LIST(),
 190};
 191
 192static void pca9548_class_init(ObjectClass *klass, void *data)
 193{
 194    DeviceClass *dc = DEVICE_CLASS(klass);
 195    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
 196
 197    k->event = pca9548_event;
 198    k->recv = pca9548_recv;
 199    k->send = pca9548_send;
 200    k->decode_address = pca9548_decode_address;
 201
 202    dc->realize = pca9548_realize;
 203    dc->reset = pca9548_reset;
 204    dc->vmsd = &vmstate_PCA9548;
 205    dc->props = pca9548_properties;
 206}
 207
 208static TypeInfo pca9548_info = {
 209    .name          = TYPE_PCA9548,
 210    .parent        = TYPE_I2C_SLAVE,
 211    .instance_size = sizeof(PCA9548State),
 212    .instance_init = pca9548_init,
 213    .class_init    = pca9548_class_init,
 214};
 215
 216static void pca9548_register_types(void)
 217{
 218    type_register_static(&pca9548_info);
 219}
 220
 221type_init(pca9548_register_types)
 222