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