qemu/hw/i2c/pca954x.c
<<
>>
Prefs
   1/*
   2 * PCA954X 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/hw.h"
  23#include "sysemu/blockdev.h"
  24#include "hw/i2c/pca954x.h"
  25#include "qemu/log.h"
  26
  27#ifndef PCA954X_DEBUG
  28#define PCA954X_DEBUG 0
  29#endif
  30
  31#define DB_PRINT(fmt, args...) do { \
  32    if (PCA954X_DEBUG) { \
  33        qemu_log("PCA954X: "fmt, ## args); \
  34    } \
  35} while (0);
  36
  37static pca954x_type known_devices[] = {
  38    /* I2C Muxes */
  39    { .name = "pca9542", .lanes = 2, .mux = true },
  40    { .name = "pca9544", .lanes = 4, .mux = true },
  41    { .name = "pca9547", .lanes = 8, .mux = true },
  42    /* I2C Switches */
  43    { .name = "pca9543", .lanes = 2, .mux = false },
  44    { .name = "pca9545", .lanes = 4, .mux = false },
  45    { .name = "pca9546", .lanes = 4, .mux = false },
  46    { .name = "pca9548", .lanes = 8, .mux = false },
  47    { .name = "pca9549", .lanes = 8, .mux = false },
  48};
  49
  50static void pca954x_reset(DeviceState *dev)
  51{
  52    PCA954XState *s = PCA954X(dev);
  53    I2CSlave *i2cs =  I2C_SLAVE(dev);
  54
  55    /* Switch decodes the enitre address range, trample any previously set
  56     * values for address and range
  57     */
  58    i2cs->address = 0;
  59    i2cs->address_range = 0x80;
  60
  61    s->control_reg = 0;
  62    s->active_lanes = 0;
  63}
  64
  65static int pca954x_recv(I2CSlave *i2c)
  66{
  67    PCA954XState *s = PCA954X(i2c);
  68    int i;
  69    int ret = 0;
  70
  71    if (s->control_decoded) {
  72        ret |= s->control_reg;
  73        DB_PRINT("returning control register: %x\n", ret);
  74    } else {
  75        for (i = 0; i < s->lanes; ++i) {
  76            if (s->active_lanes & (1 << i)) {
  77                ret |= i2c_recv(s->busses[i]);
  78                DB_PRINT("recieving from active bus %d:%x\n", i, ret);
  79            }
  80        }
  81    }
  82
  83    return ret;
  84}
  85
  86static void pca954x_decode_lane(PCA954XState *s)
  87{
  88    if (s->mux) {
  89        s->active_lanes = (1 << (s->control_reg & (s->lanes - 1)));
  90    } else {
  91        s->active_lanes = s->control_reg;
  92    }
  93}
  94
  95static int pca954x_send(I2CSlave *i2c, uint8_t data)
  96{
  97    PCA954XState *s = PCA954X(i2c);
  98    int i;
  99    int ret = -1;
 100
 101    if (s->control_decoded) {
 102        DB_PRINT("setting control register: %x\n", data);
 103        s->control_reg = data;
 104        pca954x_decode_lane(s);
 105        ret = 0;
 106    } else {
 107        for (i = 0; i < s->lanes; ++i) {
 108            if (s->active_lanes & (1 << i)) {
 109                DB_PRINT("sending to active bus %d:%x\n", i, data);
 110                ret &= i2c_send(s->busses[i], data);
 111            }
 112        }
 113    }
 114
 115    return ret;
 116}
 117
 118static int pca954x_event(I2CSlave *i2c, enum i2c_event event)
 119{
 120    PCA954XState *s = PCA954X(i2c);
 121    int i;
 122
 123    s->event = event;
 124    for (i = 0; i < s->lanes; ++i) {
 125        if (s->active_lanes & (1 << i)) {
 126            switch (event) {
 127            /* defer START conditions until we have an address */
 128            case I2C_START_SEND:
 129            case I2C_START_RECV:
 130                break;
 131            /* Forward others to sub busses */
 132            case I2C_FINISH:
 133                if (!s->control_decoded) {
 134                    DB_PRINT("stopping active bus %d\n", i);
 135                    i2c_end_transfer(s->busses[i]);
 136                }
 137                break;
 138            case I2C_NACK:
 139                if (!s->control_decoded) {
 140                    DB_PRINT("nacking active bus %d\n", i);
 141                    i2c_nack(s->busses[i]);
 142                }
 143                break;
 144            }
 145        }
 146    }
 147
 148    return 0;
 149}
 150
 151static int pca954x_decode_address(I2CSlave *i2c, uint8_t address)
 152{
 153    PCA954XState *s = PCA954X(i2c);
 154    int i;
 155    uint8_t channel_status = 0;
 156
 157    s->control_decoded = address ==
 158                    (PCA954X_CONTROL_ADDR | (s->chip_enable & 0x7));
 159
 160    if (s->control_decoded) {
 161        return 0;
 162    }
 163
 164    for (i = 0; i < s->lanes; ++i) {
 165        if (s->active_lanes & (1 << i)) {
 166            DB_PRINT("starting active bus %d addr:%02x rnw:%d\n", i, address,
 167                    s->event == I2C_START_RECV);
 168            channel_status |= (i2c_start_transfer(s->busses[i], address,
 169                               s->event == I2C_START_RECV)) << i;
 170        }
 171    }
 172
 173    if (s->active_lanes == channel_status) {
 174        return 1;
 175    }
 176
 177    return 0;
 178}
 179
 180static void pca954x_init(Object *obj)
 181{
 182    PCA954XState *s = PCA954X(obj);
 183    PCA954XClass *sc = PCA954X_GET_CLASS(obj);
 184    int i;
 185
 186    if (sc->device) {
 187        s->mux = sc->device->mux;
 188        s->lanes = sc->device->lanes;
 189    } else {
 190        /* Emulate pca9548 device as default */
 191        s->mux = false;
 192        s->lanes = 8;
 193    }
 194    for (i = 0; i < s->lanes; ++i) {
 195        char bus_name[16];
 196
 197        snprintf(bus_name, sizeof(bus_name), "i2c@%d", i);
 198        s->busses[i] = i2c_init_bus(DEVICE(s), bus_name);
 199    }
 200}
 201
 202static void pca954x_realize(DeviceState *dev, Error **errp)
 203{
 204    /* Dummy */
 205}
 206
 207static const VMStateDescription vmstate_PCA954X = {
 208    .name = "pca954x",
 209    .version_id = 1,
 210    .fields = (VMStateField[]) {
 211        VMSTATE_I2C_SLAVE(i2c, PCA954XState),
 212        VMSTATE_UINT8(control_reg, PCA954XState),
 213        VMSTATE_BOOL(control_decoded, PCA954XState),
 214        VMSTATE_UINT8(active_lanes, PCA954XState),
 215        VMSTATE_UINT8(lanes, PCA954XState),
 216        VMSTATE_BOOL(mux, PCA954XState),
 217        VMSTATE_END_OF_LIST()
 218    }
 219};
 220
 221static Property pca954x_properties[] = {
 222    /* These could be GPIOs, but the application is rare, just let machine model
 223     * tie them with props
 224     */
 225    DEFINE_PROP_UINT8("chip-enable", PCA954XState, chip_enable, 0),
 226    DEFINE_PROP_END_OF_LIST(),
 227};
 228
 229static void pca954x_class_init(ObjectClass *klass, void *data)
 230{
 231    DeviceClass *dc = DEVICE_CLASS(klass);
 232    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
 233    PCA954XClass *sc = PCA954X_CLASS(klass);
 234
 235    k->event = pca954x_event;
 236    k->recv = pca954x_recv;
 237    k->send = pca954x_send;
 238    k->decode_address = pca954x_decode_address;
 239
 240    dc->realize = pca954x_realize;
 241    dc->reset = pca954x_reset;
 242    dc->vmsd = &vmstate_PCA954X;
 243    dc->props = pca954x_properties;
 244    sc->device = data;
 245}
 246
 247static TypeInfo pca954x_info = {
 248    .name          = TYPE_PCA954X,
 249    .parent        = TYPE_I2C_SLAVE,
 250    .instance_size = sizeof(PCA954XState),
 251    .instance_init = pca954x_init,
 252};
 253
 254static void pca954x_register_types(void)
 255{
 256    int i;
 257
 258    type_register_static(&pca954x_info);
 259    for (i = 0; i < ARRAY_SIZE(known_devices); i++) {
 260        TypeInfo t = {
 261            .name = known_devices[i].name,
 262            .parent = TYPE_PCA954X,
 263            .class_init = pca954x_class_init,
 264            .class_data = &known_devices[i]
 265        };
 266        type_register(&t);
 267    }
 268}
 269
 270type_init(pca954x_register_types)
 271