xref: /openbmc/qemu/hw/gpio/bcm2838_gpio.c (revision 0c8b40db)
123c82c1dSSergey Kambalin /*
223c82c1dSSergey Kambalin  * Raspberry Pi (BCM2838) GPIO Controller
323c82c1dSSergey Kambalin  * This implementation is based on bcm2835_gpio (hw/gpio/bcm2835_gpio.c)
423c82c1dSSergey Kambalin  *
523c82c1dSSergey Kambalin  * Copyright (c) 2022 Auriga LLC
623c82c1dSSergey Kambalin  *
723c82c1dSSergey Kambalin  * Authors:
823c82c1dSSergey Kambalin  *  Lotosh, Aleksey <aleksey.lotosh@auriga.com>
923c82c1dSSergey Kambalin  *
1023c82c1dSSergey Kambalin  * SPDX-License-Identifier: GPL-2.0-or-later
1123c82c1dSSergey Kambalin  */
1223c82c1dSSergey Kambalin 
1323c82c1dSSergey Kambalin #include "qemu/osdep.h"
1423c82c1dSSergey Kambalin #include "qemu/log.h"
1523c82c1dSSergey Kambalin #include "qemu/module.h"
1623c82c1dSSergey Kambalin #include "qemu/timer.h"
1723c82c1dSSergey Kambalin #include "qapi/error.h"
1823c82c1dSSergey Kambalin #include "hw/sysbus.h"
1923c82c1dSSergey Kambalin #include "migration/vmstate.h"
2023c82c1dSSergey Kambalin #include "hw/gpio/bcm2838_gpio.h"
21*0c8b40dbSSergey Kambalin #include "hw/irq.h"
2223c82c1dSSergey Kambalin 
2323c82c1dSSergey Kambalin #define GPFSEL0   0x00
2423c82c1dSSergey Kambalin #define GPFSEL1   0x04
2523c82c1dSSergey Kambalin #define GPFSEL2   0x08
2623c82c1dSSergey Kambalin #define GPFSEL3   0x0C
2723c82c1dSSergey Kambalin #define GPFSEL4   0x10
2823c82c1dSSergey Kambalin #define GPFSEL5   0x14
2923c82c1dSSergey Kambalin #define GPSET0    0x1C
3023c82c1dSSergey Kambalin #define GPSET1    0x20
3123c82c1dSSergey Kambalin #define GPCLR0    0x28
3223c82c1dSSergey Kambalin #define GPCLR1    0x2C
3323c82c1dSSergey Kambalin #define GPLEV0    0x34
3423c82c1dSSergey Kambalin #define GPLEV1    0x38
3523c82c1dSSergey Kambalin #define GPEDS0    0x40
3623c82c1dSSergey Kambalin #define GPEDS1    0x44
3723c82c1dSSergey Kambalin #define GPREN0    0x4C
3823c82c1dSSergey Kambalin #define GPREN1    0x50
3923c82c1dSSergey Kambalin #define GPFEN0    0x58
4023c82c1dSSergey Kambalin #define GPFEN1    0x5C
4123c82c1dSSergey Kambalin #define GPHEN0    0x64
4223c82c1dSSergey Kambalin #define GPHEN1    0x68
4323c82c1dSSergey Kambalin #define GPLEN0    0x70
4423c82c1dSSergey Kambalin #define GPLEN1    0x74
4523c82c1dSSergey Kambalin #define GPAREN0   0x7C
4623c82c1dSSergey Kambalin #define GPAREN1   0x80
4723c82c1dSSergey Kambalin #define GPAFEN0   0x88
4823c82c1dSSergey Kambalin #define GPAFEN1   0x8C
4923c82c1dSSergey Kambalin 
5023c82c1dSSergey Kambalin #define GPIO_PUP_PDN_CNTRL_REG0 0xE4
5123c82c1dSSergey Kambalin #define GPIO_PUP_PDN_CNTRL_REG1 0xE8
5223c82c1dSSergey Kambalin #define GPIO_PUP_PDN_CNTRL_REG2 0xEC
5323c82c1dSSergey Kambalin #define GPIO_PUP_PDN_CNTRL_REG3 0xF0
5423c82c1dSSergey Kambalin 
5523c82c1dSSergey Kambalin #define RESET_VAL_CNTRL_REG0 0xAAA95555
5623c82c1dSSergey Kambalin #define RESET_VAL_CNTRL_REG1 0xA0AAAAAA
5723c82c1dSSergey Kambalin #define RESET_VAL_CNTRL_REG2 0x50AAA95A
5823c82c1dSSergey Kambalin #define RESET_VAL_CNTRL_REG3 0x00055555
5923c82c1dSSergey Kambalin 
60*0c8b40dbSSergey Kambalin #define NUM_FSELN_IN_GPFSELN 10
61*0c8b40dbSSergey Kambalin #define NUM_BITS_FSELN       3
62*0c8b40dbSSergey Kambalin #define MASK_FSELN           0x7
63*0c8b40dbSSergey Kambalin 
6423c82c1dSSergey Kambalin #define BYTES_IN_WORD        4
6523c82c1dSSergey Kambalin 
66*0c8b40dbSSergey Kambalin static uint32_t gpfsel_get(BCM2838GpioState *s, uint8_t reg)
67*0c8b40dbSSergey Kambalin {
68*0c8b40dbSSergey Kambalin     int i;
69*0c8b40dbSSergey Kambalin     uint32_t value = 0;
70*0c8b40dbSSergey Kambalin     for (i = 0; i < NUM_FSELN_IN_GPFSELN; i++) {
71*0c8b40dbSSergey Kambalin         uint32_t index = NUM_FSELN_IN_GPFSELN * reg + i;
72*0c8b40dbSSergey Kambalin         if (index < sizeof(s->fsel)) {
73*0c8b40dbSSergey Kambalin             value |= (s->fsel[index] & MASK_FSELN) << (NUM_BITS_FSELN * i);
74*0c8b40dbSSergey Kambalin         }
75*0c8b40dbSSergey Kambalin     }
76*0c8b40dbSSergey Kambalin     return value;
77*0c8b40dbSSergey Kambalin }
78*0c8b40dbSSergey Kambalin 
79*0c8b40dbSSergey Kambalin static void gpfsel_set(BCM2838GpioState *s, uint8_t reg, uint32_t value)
80*0c8b40dbSSergey Kambalin {
81*0c8b40dbSSergey Kambalin     int i;
82*0c8b40dbSSergey Kambalin     for (i = 0; i < NUM_FSELN_IN_GPFSELN; i++) {
83*0c8b40dbSSergey Kambalin         uint32_t index = NUM_FSELN_IN_GPFSELN * reg + i;
84*0c8b40dbSSergey Kambalin         if (index < sizeof(s->fsel)) {
85*0c8b40dbSSergey Kambalin             int fsel = (value >> (NUM_BITS_FSELN * i)) & MASK_FSELN;
86*0c8b40dbSSergey Kambalin             s->fsel[index] = fsel;
87*0c8b40dbSSergey Kambalin         }
88*0c8b40dbSSergey Kambalin     }
89*0c8b40dbSSergey Kambalin }
90*0c8b40dbSSergey Kambalin 
91*0c8b40dbSSergey Kambalin static int gpfsel_is_out(BCM2838GpioState *s, int index)
92*0c8b40dbSSergey Kambalin {
93*0c8b40dbSSergey Kambalin     if (index >= 0 && index < BCM2838_GPIO_NUM) {
94*0c8b40dbSSergey Kambalin         return s->fsel[index] == 1;
95*0c8b40dbSSergey Kambalin     }
96*0c8b40dbSSergey Kambalin     return 0;
97*0c8b40dbSSergey Kambalin }
98*0c8b40dbSSergey Kambalin 
99*0c8b40dbSSergey Kambalin static void gpset(BCM2838GpioState *s, uint32_t val, uint8_t start,
100*0c8b40dbSSergey Kambalin                   uint8_t count, uint32_t *lev)
101*0c8b40dbSSergey Kambalin {
102*0c8b40dbSSergey Kambalin     uint32_t changes = val & ~*lev;
103*0c8b40dbSSergey Kambalin     uint32_t cur = 1;
104*0c8b40dbSSergey Kambalin 
105*0c8b40dbSSergey Kambalin     int i;
106*0c8b40dbSSergey Kambalin     for (i = 0; i < count; i++) {
107*0c8b40dbSSergey Kambalin         if ((changes & cur) && (gpfsel_is_out(s, start + i))) {
108*0c8b40dbSSergey Kambalin             qemu_set_irq(s->out[start + i], 1);
109*0c8b40dbSSergey Kambalin         }
110*0c8b40dbSSergey Kambalin         cur <<= 1;
111*0c8b40dbSSergey Kambalin     }
112*0c8b40dbSSergey Kambalin 
113*0c8b40dbSSergey Kambalin     *lev |= val;
114*0c8b40dbSSergey Kambalin }
115*0c8b40dbSSergey Kambalin 
116*0c8b40dbSSergey Kambalin static void gpclr(BCM2838GpioState *s, uint32_t val, uint8_t start,
117*0c8b40dbSSergey Kambalin                   uint8_t count, uint32_t *lev)
118*0c8b40dbSSergey Kambalin {
119*0c8b40dbSSergey Kambalin     uint32_t changes = val & *lev;
120*0c8b40dbSSergey Kambalin     uint32_t cur = 1;
121*0c8b40dbSSergey Kambalin 
122*0c8b40dbSSergey Kambalin     int i;
123*0c8b40dbSSergey Kambalin     for (i = 0; i < count; i++) {
124*0c8b40dbSSergey Kambalin         if ((changes & cur) && (gpfsel_is_out(s, start + i))) {
125*0c8b40dbSSergey Kambalin             qemu_set_irq(s->out[start + i], 0);
126*0c8b40dbSSergey Kambalin         }
127*0c8b40dbSSergey Kambalin         cur <<= 1;
128*0c8b40dbSSergey Kambalin     }
129*0c8b40dbSSergey Kambalin 
130*0c8b40dbSSergey Kambalin     *lev &= ~val;
131*0c8b40dbSSergey Kambalin }
132*0c8b40dbSSergey Kambalin 
13323c82c1dSSergey Kambalin static uint64_t bcm2838_gpio_read(void *opaque, hwaddr offset, unsigned size)
13423c82c1dSSergey Kambalin {
135*0c8b40dbSSergey Kambalin     BCM2838GpioState *s = (BCM2838GpioState *)opaque;
13623c82c1dSSergey Kambalin     uint64_t value = 0;
13723c82c1dSSergey Kambalin 
138*0c8b40dbSSergey Kambalin     switch (offset) {
139*0c8b40dbSSergey Kambalin     case GPFSEL0:
140*0c8b40dbSSergey Kambalin     case GPFSEL1:
141*0c8b40dbSSergey Kambalin     case GPFSEL2:
142*0c8b40dbSSergey Kambalin     case GPFSEL3:
143*0c8b40dbSSergey Kambalin     case GPFSEL4:
144*0c8b40dbSSergey Kambalin     case GPFSEL5:
145*0c8b40dbSSergey Kambalin         value = gpfsel_get(s, offset / BYTES_IN_WORD);
146*0c8b40dbSSergey Kambalin         break;
147*0c8b40dbSSergey Kambalin     case GPSET0:
148*0c8b40dbSSergey Kambalin     case GPSET1:
149*0c8b40dbSSergey Kambalin     case GPCLR0:
150*0c8b40dbSSergey Kambalin     case GPCLR1:
151*0c8b40dbSSergey Kambalin         /* Write Only */
152*0c8b40dbSSergey Kambalin         qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: Attempt reading from write only"
153*0c8b40dbSSergey Kambalin                       " register. 0x%"PRIx64" will be returned."
154*0c8b40dbSSergey Kambalin                       " Address 0x%"HWADDR_PRIx", size %u\n",
155*0c8b40dbSSergey Kambalin                       TYPE_BCM2838_GPIO, __func__, value, offset, size);
156*0c8b40dbSSergey Kambalin         break;
157*0c8b40dbSSergey Kambalin     case GPLEV0:
158*0c8b40dbSSergey Kambalin         value = s->lev0;
159*0c8b40dbSSergey Kambalin         break;
160*0c8b40dbSSergey Kambalin     case GPLEV1:
161*0c8b40dbSSergey Kambalin         value = s->lev1;
162*0c8b40dbSSergey Kambalin         break;
163*0c8b40dbSSergey Kambalin     case GPEDS0:
164*0c8b40dbSSergey Kambalin     case GPEDS1:
165*0c8b40dbSSergey Kambalin     case GPREN0:
166*0c8b40dbSSergey Kambalin     case GPREN1:
167*0c8b40dbSSergey Kambalin     case GPFEN0:
168*0c8b40dbSSergey Kambalin     case GPFEN1:
169*0c8b40dbSSergey Kambalin     case GPHEN0:
170*0c8b40dbSSergey Kambalin     case GPHEN1:
171*0c8b40dbSSergey Kambalin     case GPLEN0:
172*0c8b40dbSSergey Kambalin     case GPLEN1:
173*0c8b40dbSSergey Kambalin     case GPAREN0:
174*0c8b40dbSSergey Kambalin     case GPAREN1:
175*0c8b40dbSSergey Kambalin     case GPAFEN0:
176*0c8b40dbSSergey Kambalin     case GPAFEN1:
177*0c8b40dbSSergey Kambalin         /* Not implemented */
17823c82c1dSSergey Kambalin         qemu_log_mask(LOG_UNIMP, "%s: %s: not implemented for %"HWADDR_PRIx"\n",
17923c82c1dSSergey Kambalin                       TYPE_BCM2838_GPIO, __func__, offset);
180*0c8b40dbSSergey Kambalin         break;
181*0c8b40dbSSergey Kambalin     case GPIO_PUP_PDN_CNTRL_REG0:
182*0c8b40dbSSergey Kambalin     case GPIO_PUP_PDN_CNTRL_REG1:
183*0c8b40dbSSergey Kambalin     case GPIO_PUP_PDN_CNTRL_REG2:
184*0c8b40dbSSergey Kambalin     case GPIO_PUP_PDN_CNTRL_REG3:
185*0c8b40dbSSergey Kambalin         value = s->pup_cntrl_reg[(offset - GPIO_PUP_PDN_CNTRL_REG0)
186*0c8b40dbSSergey Kambalin                                  / sizeof(s->pup_cntrl_reg[0])];
187*0c8b40dbSSergey Kambalin         break;
188*0c8b40dbSSergey Kambalin     default:
189*0c8b40dbSSergey Kambalin         qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: bad offset %"HWADDR_PRIx"\n",
190*0c8b40dbSSergey Kambalin                       TYPE_BCM2838_GPIO, __func__, offset);
191*0c8b40dbSSergey Kambalin         break;
192*0c8b40dbSSergey Kambalin     }
19323c82c1dSSergey Kambalin 
19423c82c1dSSergey Kambalin     return value;
19523c82c1dSSergey Kambalin }
19623c82c1dSSergey Kambalin 
19723c82c1dSSergey Kambalin static void bcm2838_gpio_write(void *opaque, hwaddr offset, uint64_t value,
19823c82c1dSSergey Kambalin                                unsigned size)
19923c82c1dSSergey Kambalin {
200*0c8b40dbSSergey Kambalin     BCM2838GpioState *s = (BCM2838GpioState *)opaque;
201*0c8b40dbSSergey Kambalin 
202*0c8b40dbSSergey Kambalin     switch (offset) {
203*0c8b40dbSSergey Kambalin     case GPFSEL0:
204*0c8b40dbSSergey Kambalin     case GPFSEL1:
205*0c8b40dbSSergey Kambalin     case GPFSEL2:
206*0c8b40dbSSergey Kambalin     case GPFSEL3:
207*0c8b40dbSSergey Kambalin     case GPFSEL4:
208*0c8b40dbSSergey Kambalin     case GPFSEL5:
209*0c8b40dbSSergey Kambalin         gpfsel_set(s, offset / BYTES_IN_WORD, value);
210*0c8b40dbSSergey Kambalin         break;
211*0c8b40dbSSergey Kambalin     case GPSET0:
212*0c8b40dbSSergey Kambalin         gpset(s, value, 0, 32, &s->lev0);
213*0c8b40dbSSergey Kambalin         break;
214*0c8b40dbSSergey Kambalin     case GPSET1:
215*0c8b40dbSSergey Kambalin         gpset(s, value, 32, 22, &s->lev1);
216*0c8b40dbSSergey Kambalin         break;
217*0c8b40dbSSergey Kambalin     case GPCLR0:
218*0c8b40dbSSergey Kambalin         gpclr(s, value, 0, 32, &s->lev0);
219*0c8b40dbSSergey Kambalin         break;
220*0c8b40dbSSergey Kambalin     case GPCLR1:
221*0c8b40dbSSergey Kambalin         gpclr(s, value, 32, 22, &s->lev1);
222*0c8b40dbSSergey Kambalin         break;
223*0c8b40dbSSergey Kambalin     case GPLEV0:
224*0c8b40dbSSergey Kambalin     case GPLEV1:
225*0c8b40dbSSergey Kambalin         /* Read Only */
226*0c8b40dbSSergey Kambalin         qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: Attempt writing 0x%"PRIx64""
227*0c8b40dbSSergey Kambalin                       " to read only register. Ignored."
228*0c8b40dbSSergey Kambalin                       " Address 0x%"HWADDR_PRIx", size %u\n",
229*0c8b40dbSSergey Kambalin                       TYPE_BCM2838_GPIO, __func__, value, offset, size);
230*0c8b40dbSSergey Kambalin         break;
231*0c8b40dbSSergey Kambalin     case GPEDS0:
232*0c8b40dbSSergey Kambalin     case GPEDS1:
233*0c8b40dbSSergey Kambalin     case GPREN0:
234*0c8b40dbSSergey Kambalin     case GPREN1:
235*0c8b40dbSSergey Kambalin     case GPFEN0:
236*0c8b40dbSSergey Kambalin     case GPFEN1:
237*0c8b40dbSSergey Kambalin     case GPHEN0:
238*0c8b40dbSSergey Kambalin     case GPHEN1:
239*0c8b40dbSSergey Kambalin     case GPLEN0:
240*0c8b40dbSSergey Kambalin     case GPLEN1:
241*0c8b40dbSSergey Kambalin     case GPAREN0:
242*0c8b40dbSSergey Kambalin     case GPAREN1:
243*0c8b40dbSSergey Kambalin     case GPAFEN0:
244*0c8b40dbSSergey Kambalin     case GPAFEN1:
245*0c8b40dbSSergey Kambalin         /* Not implemented */
24623c82c1dSSergey Kambalin         qemu_log_mask(LOG_UNIMP, "%s: %s: not implemented for %"HWADDR_PRIx"\n",
24723c82c1dSSergey Kambalin                       TYPE_BCM2838_GPIO, __func__, offset);
248*0c8b40dbSSergey Kambalin         break;
249*0c8b40dbSSergey Kambalin     case GPIO_PUP_PDN_CNTRL_REG0:
250*0c8b40dbSSergey Kambalin     case GPIO_PUP_PDN_CNTRL_REG1:
251*0c8b40dbSSergey Kambalin     case GPIO_PUP_PDN_CNTRL_REG2:
252*0c8b40dbSSergey Kambalin     case GPIO_PUP_PDN_CNTRL_REG3:
253*0c8b40dbSSergey Kambalin         s->pup_cntrl_reg[(offset - GPIO_PUP_PDN_CNTRL_REG0)
254*0c8b40dbSSergey Kambalin                          / sizeof(s->pup_cntrl_reg[0])] = value;
255*0c8b40dbSSergey Kambalin         break;
256*0c8b40dbSSergey Kambalin     default:
257*0c8b40dbSSergey Kambalin         qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: bad offset %"HWADDR_PRIx"\n",
258*0c8b40dbSSergey Kambalin                   TYPE_BCM2838_GPIO, __func__, offset);
259*0c8b40dbSSergey Kambalin     }
260*0c8b40dbSSergey Kambalin     return;
26123c82c1dSSergey Kambalin }
26223c82c1dSSergey Kambalin 
26323c82c1dSSergey Kambalin static void bcm2838_gpio_reset(DeviceState *dev)
26423c82c1dSSergey Kambalin {
26523c82c1dSSergey Kambalin     BCM2838GpioState *s = BCM2838_GPIO(dev);
26623c82c1dSSergey Kambalin 
267*0c8b40dbSSergey Kambalin     memset(s->fsel, 0, sizeof(s->fsel));
268*0c8b40dbSSergey Kambalin 
26923c82c1dSSergey Kambalin     s->lev0 = 0;
27023c82c1dSSergey Kambalin     s->lev1 = 0;
27123c82c1dSSergey Kambalin 
27223c82c1dSSergey Kambalin     memset(s->fsel, 0, sizeof(s->fsel));
27323c82c1dSSergey Kambalin 
27423c82c1dSSergey Kambalin     s->pup_cntrl_reg[0] = RESET_VAL_CNTRL_REG0;
27523c82c1dSSergey Kambalin     s->pup_cntrl_reg[1] = RESET_VAL_CNTRL_REG1;
27623c82c1dSSergey Kambalin     s->pup_cntrl_reg[2] = RESET_VAL_CNTRL_REG2;
27723c82c1dSSergey Kambalin     s->pup_cntrl_reg[3] = RESET_VAL_CNTRL_REG3;
27823c82c1dSSergey Kambalin }
27923c82c1dSSergey Kambalin 
28023c82c1dSSergey Kambalin static const MemoryRegionOps bcm2838_gpio_ops = {
28123c82c1dSSergey Kambalin     .read = bcm2838_gpio_read,
28223c82c1dSSergey Kambalin     .write = bcm2838_gpio_write,
28323c82c1dSSergey Kambalin     .endianness = DEVICE_NATIVE_ENDIAN,
28423c82c1dSSergey Kambalin };
28523c82c1dSSergey Kambalin 
28623c82c1dSSergey Kambalin static const VMStateDescription vmstate_bcm2838_gpio = {
28723c82c1dSSergey Kambalin     .name = "bcm2838_gpio",
28823c82c1dSSergey Kambalin     .version_id = 1,
28923c82c1dSSergey Kambalin     .minimum_version_id = 1,
29023c82c1dSSergey Kambalin     .fields = (VMStateField[]) {
29123c82c1dSSergey Kambalin         VMSTATE_UINT8_ARRAY(fsel, BCM2838GpioState, BCM2838_GPIO_NUM),
29223c82c1dSSergey Kambalin         VMSTATE_UINT32(lev0, BCM2838GpioState),
29323c82c1dSSergey Kambalin         VMSTATE_UINT32(lev1, BCM2838GpioState),
29423c82c1dSSergey Kambalin         VMSTATE_UINT8(sd_fsel, BCM2838GpioState),
29523c82c1dSSergey Kambalin         VMSTATE_UINT32_ARRAY(pup_cntrl_reg, BCM2838GpioState,
29623c82c1dSSergey Kambalin                              GPIO_PUP_PDN_CNTRL_NUM),
29723c82c1dSSergey Kambalin         VMSTATE_END_OF_LIST()
29823c82c1dSSergey Kambalin     }
29923c82c1dSSergey Kambalin };
30023c82c1dSSergey Kambalin 
30123c82c1dSSergey Kambalin static void bcm2838_gpio_init(Object *obj)
30223c82c1dSSergey Kambalin {
30323c82c1dSSergey Kambalin     BCM2838GpioState *s = BCM2838_GPIO(obj);
30423c82c1dSSergey Kambalin     DeviceState *dev = DEVICE(obj);
30523c82c1dSSergey Kambalin     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
30623c82c1dSSergey Kambalin 
30723c82c1dSSergey Kambalin     memory_region_init_io(&s->iomem, obj, &bcm2838_gpio_ops, s,
30823c82c1dSSergey Kambalin                           "bcm2838_gpio", BCM2838_GPIO_REGS_SIZE);
30923c82c1dSSergey Kambalin     sysbus_init_mmio(sbd, &s->iomem);
31023c82c1dSSergey Kambalin     qdev_init_gpio_out(dev, s->out, BCM2838_GPIO_NUM);
31123c82c1dSSergey Kambalin }
31223c82c1dSSergey Kambalin 
31323c82c1dSSergey Kambalin static void bcm2838_gpio_realize(DeviceState *dev, Error **errp)
31423c82c1dSSergey Kambalin {
31523c82c1dSSergey Kambalin     /* Temporary stub. Do nothing */
31623c82c1dSSergey Kambalin }
31723c82c1dSSergey Kambalin 
31823c82c1dSSergey Kambalin static void bcm2838_gpio_class_init(ObjectClass *klass, void *data)
31923c82c1dSSergey Kambalin {
32023c82c1dSSergey Kambalin     DeviceClass *dc = DEVICE_CLASS(klass);
32123c82c1dSSergey Kambalin 
32223c82c1dSSergey Kambalin     dc->vmsd = &vmstate_bcm2838_gpio;
32323c82c1dSSergey Kambalin     dc->realize = &bcm2838_gpio_realize;
32423c82c1dSSergey Kambalin     dc->reset = &bcm2838_gpio_reset;
32523c82c1dSSergey Kambalin }
32623c82c1dSSergey Kambalin 
32723c82c1dSSergey Kambalin static const TypeInfo bcm2838_gpio_info = {
32823c82c1dSSergey Kambalin     .name          = TYPE_BCM2838_GPIO,
32923c82c1dSSergey Kambalin     .parent        = TYPE_SYS_BUS_DEVICE,
33023c82c1dSSergey Kambalin     .instance_size = sizeof(BCM2838GpioState),
33123c82c1dSSergey Kambalin     .instance_init = bcm2838_gpio_init,
33223c82c1dSSergey Kambalin     .class_init    = bcm2838_gpio_class_init,
33323c82c1dSSergey Kambalin };
33423c82c1dSSergey Kambalin 
33523c82c1dSSergey Kambalin static void bcm2838_gpio_register_types(void)
33623c82c1dSSergey Kambalin {
33723c82c1dSSergey Kambalin     type_register_static(&bcm2838_gpio_info);
33823c82c1dSSergey Kambalin }
33923c82c1dSSergey Kambalin 
34023c82c1dSSergey Kambalin type_init(bcm2838_gpio_register_types)
341