qemu/hw/i2c/versatile_i2c.c
<<
>>
Prefs
   1/*
   2 * ARM SBCon two-wire serial bus interface (I2C bitbang)
   3 * a.k.a. ARM Versatile I2C controller
   4 *
   5 * Copyright (c) 2006-2007 CodeSourcery.
   6 * Copyright (c) 2012 Oskar Andero <oskar.andero@gmail.com>
   7 *
   8 * This file is derived from hw/realview.c by Paul Brook
   9 *
  10 * This program is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU General Public License
  12 * as published by the Free Software Foundation; either version 2
  13 * of the License, or (at your option) any later version.
  14 *
  15 * This program is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 * GNU General Public License for more details.
  19 *
  20 * You should have received a copy of the GNU General Public License
  21 * along with this program; if not, see <http://www.gnu.org/licenses/>.
  22 *
  23 */
  24
  25#include "qemu/osdep.h"
  26#include "hw/i2c/arm_sbcon_i2c.h"
  27#include "hw/registerfields.h"
  28#include "qemu/log.h"
  29#include "qemu/module.h"
  30#include "qom/object.h"
  31
  32typedef ArmSbconI2CState VersatileI2CState;
  33DECLARE_INSTANCE_CHECKER(VersatileI2CState, VERSATILE_I2C,
  34                         TYPE_VERSATILE_I2C)
  35
  36
  37
  38REG32(CONTROL_GET, 0)
  39REG32(CONTROL_SET, 0)
  40REG32(CONTROL_CLR, 4)
  41
  42#define SCL BIT(0)
  43#define SDA BIT(1)
  44
  45static uint64_t versatile_i2c_read(void *opaque, hwaddr offset,
  46                                   unsigned size)
  47{
  48    VersatileI2CState *s = (VersatileI2CState *)opaque;
  49
  50    switch (offset) {
  51    case A_CONTROL_SET:
  52        return (s->out & 1) | (s->in << 1);
  53    default:
  54        qemu_log_mask(LOG_GUEST_ERROR,
  55                      "%s: Bad offset 0x%x\n", __func__, (int)offset);
  56        return -1;
  57    }
  58}
  59
  60static void versatile_i2c_write(void *opaque, hwaddr offset,
  61                                uint64_t value, unsigned size)
  62{
  63    VersatileI2CState *s = (VersatileI2CState *)opaque;
  64
  65    switch (offset) {
  66    case A_CONTROL_SET:
  67        s->out |= value & 3;
  68        break;
  69    case A_CONTROL_CLR:
  70        s->out &= ~value;
  71        break;
  72    default:
  73        qemu_log_mask(LOG_GUEST_ERROR,
  74                      "%s: Bad offset 0x%x\n", __func__, (int)offset);
  75    }
  76    bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SCL, (s->out & SCL) != 0);
  77    s->in = bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SDA, (s->out & SDA) != 0);
  78}
  79
  80static const MemoryRegionOps versatile_i2c_ops = {
  81    .read = versatile_i2c_read,
  82    .write = versatile_i2c_write,
  83    .endianness = DEVICE_NATIVE_ENDIAN,
  84};
  85
  86static void versatile_i2c_init(Object *obj)
  87{
  88    DeviceState *dev = DEVICE(obj);
  89    VersatileI2CState *s = VERSATILE_I2C(obj);
  90    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
  91    I2CBus *bus;
  92
  93    bus = i2c_init_bus(dev, "i2c");
  94    bitbang_i2c_init(&s->bitbang, bus);
  95    memory_region_init_io(&s->iomem, obj, &versatile_i2c_ops, s,
  96                          "arm_sbcon_i2c", 0x1000);
  97    sysbus_init_mmio(sbd, &s->iomem);
  98}
  99
 100static const TypeInfo versatile_i2c_info = {
 101    .name          = TYPE_VERSATILE_I2C,
 102    .parent        = TYPE_SYS_BUS_DEVICE,
 103    .instance_size = sizeof(VersatileI2CState),
 104    .instance_init = versatile_i2c_init,
 105};
 106
 107static void versatile_i2c_register_types(void)
 108{
 109    type_register_static(&versatile_i2c_info);
 110}
 111
 112type_init(versatile_i2c_register_types)
 113