xref: /openbmc/qemu/hw/i2c/arm_sbcon_i2c.c (revision 500a64d8)
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