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