1f4427280SJean-Christophe Dubois /* 2f4427280SJean-Christophe Dubois * i.MX processors GPIO emulation. 3f4427280SJean-Christophe Dubois * 4f4427280SJean-Christophe Dubois * Copyright (C) 2015 Jean-Christophe Dubois <jcd@tribudubois.net> 5f4427280SJean-Christophe Dubois * 6f4427280SJean-Christophe Dubois * This program is free software; you can redistribute it and/or 7f4427280SJean-Christophe Dubois * modify it under the terms of the GNU General Public License as 8f4427280SJean-Christophe Dubois * published by the Free Software Foundation; either version 2 or 9f4427280SJean-Christophe Dubois * (at your option) version 3 of the License. 10f4427280SJean-Christophe Dubois * 11f4427280SJean-Christophe Dubois * This program is distributed in the hope that it will be useful, 12f4427280SJean-Christophe Dubois * but WITHOUT ANY WARRANTY; without even the implied warranty of 13f4427280SJean-Christophe Dubois * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14f4427280SJean-Christophe Dubois * GNU General Public License for more details. 15f4427280SJean-Christophe Dubois * 16f4427280SJean-Christophe Dubois * You should have received a copy of the GNU General Public License along 17f4427280SJean-Christophe Dubois * with this program; if not, see <http://www.gnu.org/licenses/>. 18f4427280SJean-Christophe Dubois */ 19f4427280SJean-Christophe Dubois 208ef94f0bSPeter Maydell #include "qemu/osdep.h" 21f4427280SJean-Christophe Dubois #include "hw/gpio/imx_gpio.h" 2264552b6bSMarkus Armbruster #include "hw/irq.h" 23*a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 24d6454270SMarkus Armbruster #include "migration/vmstate.h" 2503dd024fSPaolo Bonzini #include "qemu/log.h" 260b8fa32fSMarkus Armbruster #include "qemu/module.h" 27f4427280SJean-Christophe Dubois 28f4427280SJean-Christophe Dubois #ifndef DEBUG_IMX_GPIO 29f4427280SJean-Christophe Dubois #define DEBUG_IMX_GPIO 0 30f4427280SJean-Christophe Dubois #endif 31f4427280SJean-Christophe Dubois 32f4427280SJean-Christophe Dubois typedef enum IMXGPIOLevel { 33f4427280SJean-Christophe Dubois IMX_GPIO_LEVEL_LOW = 0, 34f4427280SJean-Christophe Dubois IMX_GPIO_LEVEL_HIGH = 1, 35f4427280SJean-Christophe Dubois } IMXGPIOLevel; 36f4427280SJean-Christophe Dubois 37f4427280SJean-Christophe Dubois #define DPRINTF(fmt, args...) \ 38f4427280SJean-Christophe Dubois do { \ 39f4427280SJean-Christophe Dubois if (DEBUG_IMX_GPIO) { \ 4056411125SJean-Christophe Dubois fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_GPIO, \ 4156411125SJean-Christophe Dubois __func__, ##args); \ 42f4427280SJean-Christophe Dubois } \ 43f4427280SJean-Christophe Dubois } while (0) 44f4427280SJean-Christophe Dubois 45f4427280SJean-Christophe Dubois static const char *imx_gpio_reg_name(uint32_t reg) 46f4427280SJean-Christophe Dubois { 47f4427280SJean-Christophe Dubois switch (reg) { 48f4427280SJean-Christophe Dubois case DR_ADDR: 49f4427280SJean-Christophe Dubois return "DR"; 50f4427280SJean-Christophe Dubois case GDIR_ADDR: 51f4427280SJean-Christophe Dubois return "GDIR"; 52f4427280SJean-Christophe Dubois case PSR_ADDR: 53f4427280SJean-Christophe Dubois return "PSR"; 54f4427280SJean-Christophe Dubois case ICR1_ADDR: 55f4427280SJean-Christophe Dubois return "ICR1"; 56f4427280SJean-Christophe Dubois case ICR2_ADDR: 57f4427280SJean-Christophe Dubois return "ICR2"; 58f4427280SJean-Christophe Dubois case IMR_ADDR: 59f4427280SJean-Christophe Dubois return "IMR"; 60f4427280SJean-Christophe Dubois case ISR_ADDR: 61f4427280SJean-Christophe Dubois return "ISR"; 62f4427280SJean-Christophe Dubois case EDGE_SEL_ADDR: 63f4427280SJean-Christophe Dubois return "EDGE_SEL"; 64f4427280SJean-Christophe Dubois default: 65f4427280SJean-Christophe Dubois return "[?]"; 66f4427280SJean-Christophe Dubois } 67f4427280SJean-Christophe Dubois } 68f4427280SJean-Christophe Dubois 69f4427280SJean-Christophe Dubois static void imx_gpio_update_int(IMXGPIOState *s) 70f4427280SJean-Christophe Dubois { 71f1f7e4bfSJean-Christophe Dubois if (s->has_upper_pin_irq) { 72f1f7e4bfSJean-Christophe Dubois qemu_set_irq(s->irq[0], (s->isr & s->imr & 0x0000FFFF) ? 1 : 0); 73f1f7e4bfSJean-Christophe Dubois qemu_set_irq(s->irq[1], (s->isr & s->imr & 0xFFFF0000) ? 1 : 0); 74f1f7e4bfSJean-Christophe Dubois } else { 75f1f7e4bfSJean-Christophe Dubois qemu_set_irq(s->irq[0], (s->isr & s->imr) ? 1 : 0); 76f1f7e4bfSJean-Christophe Dubois } 77f4427280SJean-Christophe Dubois } 78f4427280SJean-Christophe Dubois 79f4427280SJean-Christophe Dubois static void imx_gpio_set_int_line(IMXGPIOState *s, int line, IMXGPIOLevel level) 80f4427280SJean-Christophe Dubois { 81f4427280SJean-Christophe Dubois /* if this signal isn't configured as an input signal, nothing to do */ 82f4427280SJean-Christophe Dubois if (!extract32(s->gdir, line, 1)) { 83f4427280SJean-Christophe Dubois return; 84f4427280SJean-Christophe Dubois } 85f4427280SJean-Christophe Dubois 86f4427280SJean-Christophe Dubois /* When set, EDGE_SEL overrides the ICR config */ 87f4427280SJean-Christophe Dubois if (extract32(s->edge_sel, line, 1)) { 88f4427280SJean-Christophe Dubois /* we detect interrupt on rising and falling edge */ 89f4427280SJean-Christophe Dubois if (extract32(s->psr, line, 1) != level) { 90f4427280SJean-Christophe Dubois /* level changed */ 91f4427280SJean-Christophe Dubois s->isr = deposit32(s->isr, line, 1, 1); 92f4427280SJean-Christophe Dubois } 93f4427280SJean-Christophe Dubois } else if (extract64(s->icr, 2*line + 1, 1)) { 94f4427280SJean-Christophe Dubois /* interrupt is edge sensitive */ 95f4427280SJean-Christophe Dubois if (extract32(s->psr, line, 1) != level) { 96f4427280SJean-Christophe Dubois /* level changed */ 97f4427280SJean-Christophe Dubois if (extract64(s->icr, 2*line, 1) != level) { 98f4427280SJean-Christophe Dubois s->isr = deposit32(s->isr, line, 1, 1); 99f4427280SJean-Christophe Dubois } 100f4427280SJean-Christophe Dubois } 101f4427280SJean-Christophe Dubois } else { 102f4427280SJean-Christophe Dubois /* interrupt is level sensitive */ 103f4427280SJean-Christophe Dubois if (extract64(s->icr, 2*line, 1) == level) { 104f4427280SJean-Christophe Dubois s->isr = deposit32(s->isr, line, 1, 1); 105f4427280SJean-Christophe Dubois } 106f4427280SJean-Christophe Dubois } 107f4427280SJean-Christophe Dubois } 108f4427280SJean-Christophe Dubois 109f4427280SJean-Christophe Dubois static void imx_gpio_set(void *opaque, int line, int level) 110f4427280SJean-Christophe Dubois { 111f4427280SJean-Christophe Dubois IMXGPIOState *s = IMX_GPIO(opaque); 112f4427280SJean-Christophe Dubois IMXGPIOLevel imx_level = level ? IMX_GPIO_LEVEL_HIGH : IMX_GPIO_LEVEL_LOW; 113f4427280SJean-Christophe Dubois 114f4427280SJean-Christophe Dubois imx_gpio_set_int_line(s, line, imx_level); 115f4427280SJean-Christophe Dubois 116f4427280SJean-Christophe Dubois /* this is an input signal, so set PSR */ 117f4427280SJean-Christophe Dubois s->psr = deposit32(s->psr, line, 1, imx_level); 118f4427280SJean-Christophe Dubois 119f4427280SJean-Christophe Dubois imx_gpio_update_int(s); 120f4427280SJean-Christophe Dubois } 121f4427280SJean-Christophe Dubois 122f4427280SJean-Christophe Dubois static void imx_gpio_set_all_int_lines(IMXGPIOState *s) 123f4427280SJean-Christophe Dubois { 124f4427280SJean-Christophe Dubois int i; 125f4427280SJean-Christophe Dubois 126f4427280SJean-Christophe Dubois for (i = 0; i < IMX_GPIO_PIN_COUNT; i++) { 127f4427280SJean-Christophe Dubois IMXGPIOLevel imx_level = extract32(s->psr, i, 1); 128f4427280SJean-Christophe Dubois imx_gpio_set_int_line(s, i, imx_level); 129f4427280SJean-Christophe Dubois } 130f4427280SJean-Christophe Dubois 131f4427280SJean-Christophe Dubois imx_gpio_update_int(s); 132f4427280SJean-Christophe Dubois } 133f4427280SJean-Christophe Dubois 134f4427280SJean-Christophe Dubois static inline void imx_gpio_set_all_output_lines(IMXGPIOState *s) 135f4427280SJean-Christophe Dubois { 136f4427280SJean-Christophe Dubois int i; 137f4427280SJean-Christophe Dubois 138f4427280SJean-Christophe Dubois for (i = 0; i < IMX_GPIO_PIN_COUNT; i++) { 139f4427280SJean-Christophe Dubois /* 140f4427280SJean-Christophe Dubois * if the line is set as output, then forward the line 141f4427280SJean-Christophe Dubois * level to its user. 142f4427280SJean-Christophe Dubois */ 143f4427280SJean-Christophe Dubois if (extract32(s->gdir, i, 1) && s->output[i]) { 144f4427280SJean-Christophe Dubois qemu_set_irq(s->output[i], extract32(s->dr, i, 1)); 145f4427280SJean-Christophe Dubois } 146f4427280SJean-Christophe Dubois } 147f4427280SJean-Christophe Dubois } 148f4427280SJean-Christophe Dubois 149f4427280SJean-Christophe Dubois static uint64_t imx_gpio_read(void *opaque, hwaddr offset, unsigned size) 150f4427280SJean-Christophe Dubois { 151f4427280SJean-Christophe Dubois IMXGPIOState *s = IMX_GPIO(opaque); 152f4427280SJean-Christophe Dubois uint32_t reg_value = 0; 153f4427280SJean-Christophe Dubois 154f4427280SJean-Christophe Dubois switch (offset) { 155f4427280SJean-Christophe Dubois case DR_ADDR: 156f4427280SJean-Christophe Dubois /* 157f4427280SJean-Christophe Dubois * depending on the "line" configuration, the bit values 158f4427280SJean-Christophe Dubois * are coming either from DR or PSR 159f4427280SJean-Christophe Dubois */ 160f4427280SJean-Christophe Dubois reg_value = (s->dr & s->gdir) | (s->psr & ~s->gdir); 161f4427280SJean-Christophe Dubois break; 162f4427280SJean-Christophe Dubois 163f4427280SJean-Christophe Dubois case GDIR_ADDR: 164f4427280SJean-Christophe Dubois reg_value = s->gdir; 165f4427280SJean-Christophe Dubois break; 166f4427280SJean-Christophe Dubois 167f4427280SJean-Christophe Dubois case PSR_ADDR: 168f4427280SJean-Christophe Dubois reg_value = s->psr & ~s->gdir; 169f4427280SJean-Christophe Dubois break; 170f4427280SJean-Christophe Dubois 171f4427280SJean-Christophe Dubois case ICR1_ADDR: 172f4427280SJean-Christophe Dubois reg_value = extract64(s->icr, 0, 32); 173f4427280SJean-Christophe Dubois break; 174f4427280SJean-Christophe Dubois 175f4427280SJean-Christophe Dubois case ICR2_ADDR: 176f4427280SJean-Christophe Dubois reg_value = extract64(s->icr, 32, 32); 177f4427280SJean-Christophe Dubois break; 178f4427280SJean-Christophe Dubois 179f4427280SJean-Christophe Dubois case IMR_ADDR: 180f4427280SJean-Christophe Dubois reg_value = s->imr; 181f4427280SJean-Christophe Dubois break; 182f4427280SJean-Christophe Dubois 183f4427280SJean-Christophe Dubois case ISR_ADDR: 184f4427280SJean-Christophe Dubois reg_value = s->isr; 185f4427280SJean-Christophe Dubois break; 186f4427280SJean-Christophe Dubois 187f4427280SJean-Christophe Dubois case EDGE_SEL_ADDR: 188f4427280SJean-Christophe Dubois if (s->has_edge_sel) { 189f4427280SJean-Christophe Dubois reg_value = s->edge_sel; 190f4427280SJean-Christophe Dubois } else { 19156411125SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: EDGE_SEL register not " 192f4427280SJean-Christophe Dubois "present on this version of GPIO device\n", 193f4427280SJean-Christophe Dubois TYPE_IMX_GPIO, __func__); 194f4427280SJean-Christophe Dubois } 195f4427280SJean-Christophe Dubois break; 196f4427280SJean-Christophe Dubois 197f4427280SJean-Christophe Dubois default: 19856411125SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" 19956411125SJean-Christophe Dubois HWADDR_PRIx "\n", TYPE_IMX_GPIO, __func__, offset); 200f4427280SJean-Christophe Dubois break; 201f4427280SJean-Christophe Dubois } 202f4427280SJean-Christophe Dubois 203f4427280SJean-Christophe Dubois DPRINTF("(%s) = 0x%" PRIx32 "\n", imx_gpio_reg_name(offset), reg_value); 204f4427280SJean-Christophe Dubois 205f4427280SJean-Christophe Dubois return reg_value; 206f4427280SJean-Christophe Dubois } 207f4427280SJean-Christophe Dubois 208f4427280SJean-Christophe Dubois static void imx_gpio_write(void *opaque, hwaddr offset, uint64_t value, 209f4427280SJean-Christophe Dubois unsigned size) 210f4427280SJean-Christophe Dubois { 211f4427280SJean-Christophe Dubois IMXGPIOState *s = IMX_GPIO(opaque); 212f4427280SJean-Christophe Dubois 213f4427280SJean-Christophe Dubois DPRINTF("(%s, value = 0x%" PRIx32 ")\n", imx_gpio_reg_name(offset), 214f4427280SJean-Christophe Dubois (uint32_t)value); 215f4427280SJean-Christophe Dubois 216f4427280SJean-Christophe Dubois switch (offset) { 217f4427280SJean-Christophe Dubois case DR_ADDR: 218f4427280SJean-Christophe Dubois s->dr = value; 219f4427280SJean-Christophe Dubois imx_gpio_set_all_output_lines(s); 220f4427280SJean-Christophe Dubois break; 221f4427280SJean-Christophe Dubois 222f4427280SJean-Christophe Dubois case GDIR_ADDR: 223f4427280SJean-Christophe Dubois s->gdir = value; 224f4427280SJean-Christophe Dubois imx_gpio_set_all_output_lines(s); 225f4427280SJean-Christophe Dubois imx_gpio_set_all_int_lines(s); 226f4427280SJean-Christophe Dubois break; 227f4427280SJean-Christophe Dubois 228f4427280SJean-Christophe Dubois case ICR1_ADDR: 229f4427280SJean-Christophe Dubois s->icr = deposit64(s->icr, 0, 32, value); 230f4427280SJean-Christophe Dubois imx_gpio_set_all_int_lines(s); 231f4427280SJean-Christophe Dubois break; 232f4427280SJean-Christophe Dubois 233f4427280SJean-Christophe Dubois case ICR2_ADDR: 234f4427280SJean-Christophe Dubois s->icr = deposit64(s->icr, 32, 32, value); 235f4427280SJean-Christophe Dubois imx_gpio_set_all_int_lines(s); 236f4427280SJean-Christophe Dubois break; 237f4427280SJean-Christophe Dubois 238f4427280SJean-Christophe Dubois case IMR_ADDR: 239f4427280SJean-Christophe Dubois s->imr = value; 240f4427280SJean-Christophe Dubois imx_gpio_update_int(s); 241f4427280SJean-Christophe Dubois break; 242f4427280SJean-Christophe Dubois 243f4427280SJean-Christophe Dubois case ISR_ADDR: 244fb70029bSGuenter Roeck s->isr &= ~value; 245f4427280SJean-Christophe Dubois imx_gpio_set_all_int_lines(s); 246f4427280SJean-Christophe Dubois break; 247f4427280SJean-Christophe Dubois 248f4427280SJean-Christophe Dubois case EDGE_SEL_ADDR: 249f4427280SJean-Christophe Dubois if (s->has_edge_sel) { 250f4427280SJean-Christophe Dubois s->edge_sel = value; 251f4427280SJean-Christophe Dubois imx_gpio_set_all_int_lines(s); 252f4427280SJean-Christophe Dubois } else { 25356411125SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: EDGE_SEL register not " 254f4427280SJean-Christophe Dubois "present on this version of GPIO device\n", 255f4427280SJean-Christophe Dubois TYPE_IMX_GPIO, __func__); 256f4427280SJean-Christophe Dubois } 257f4427280SJean-Christophe Dubois break; 258f4427280SJean-Christophe Dubois 259f4427280SJean-Christophe Dubois default: 26056411125SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" 26156411125SJean-Christophe Dubois HWADDR_PRIx "\n", TYPE_IMX_GPIO, __func__, offset); 262f4427280SJean-Christophe Dubois break; 263f4427280SJean-Christophe Dubois } 264f4427280SJean-Christophe Dubois 265f4427280SJean-Christophe Dubois return; 266f4427280SJean-Christophe Dubois } 267f4427280SJean-Christophe Dubois 268f4427280SJean-Christophe Dubois static const MemoryRegionOps imx_gpio_ops = { 269f4427280SJean-Christophe Dubois .read = imx_gpio_read, 270f4427280SJean-Christophe Dubois .write = imx_gpio_write, 271f4427280SJean-Christophe Dubois .valid.min_access_size = 4, 272f4427280SJean-Christophe Dubois .valid.max_access_size = 4, 273f4427280SJean-Christophe Dubois .endianness = DEVICE_NATIVE_ENDIAN, 274f4427280SJean-Christophe Dubois }; 275f4427280SJean-Christophe Dubois 276f4427280SJean-Christophe Dubois static const VMStateDescription vmstate_imx_gpio = { 277f4427280SJean-Christophe Dubois .name = TYPE_IMX_GPIO, 278f4427280SJean-Christophe Dubois .version_id = 1, 279f4427280SJean-Christophe Dubois .minimum_version_id = 1, 280f4427280SJean-Christophe Dubois .minimum_version_id_old = 1, 281f4427280SJean-Christophe Dubois .fields = (VMStateField[]) { 282f4427280SJean-Christophe Dubois VMSTATE_UINT32(dr, IMXGPIOState), 283f4427280SJean-Christophe Dubois VMSTATE_UINT32(gdir, IMXGPIOState), 284f4427280SJean-Christophe Dubois VMSTATE_UINT32(psr, IMXGPIOState), 285f4427280SJean-Christophe Dubois VMSTATE_UINT64(icr, IMXGPIOState), 286f4427280SJean-Christophe Dubois VMSTATE_UINT32(imr, IMXGPIOState), 287f4427280SJean-Christophe Dubois VMSTATE_UINT32(isr, IMXGPIOState), 288f4427280SJean-Christophe Dubois VMSTATE_BOOL(has_edge_sel, IMXGPIOState), 289f4427280SJean-Christophe Dubois VMSTATE_UINT32(edge_sel, IMXGPIOState), 290f4427280SJean-Christophe Dubois VMSTATE_END_OF_LIST() 291f4427280SJean-Christophe Dubois } 292f4427280SJean-Christophe Dubois }; 293f4427280SJean-Christophe Dubois 294f4427280SJean-Christophe Dubois static Property imx_gpio_properties[] = { 295f4427280SJean-Christophe Dubois DEFINE_PROP_BOOL("has-edge-sel", IMXGPIOState, has_edge_sel, true), 296f1f7e4bfSJean-Christophe Dubois DEFINE_PROP_BOOL("has-upper-pin-irq", IMXGPIOState, has_upper_pin_irq, 297f1f7e4bfSJean-Christophe Dubois false), 298f4427280SJean-Christophe Dubois DEFINE_PROP_END_OF_LIST(), 299f4427280SJean-Christophe Dubois }; 300f4427280SJean-Christophe Dubois 301f4427280SJean-Christophe Dubois static void imx_gpio_reset(DeviceState *dev) 302f4427280SJean-Christophe Dubois { 303f4427280SJean-Christophe Dubois IMXGPIOState *s = IMX_GPIO(dev); 304f4427280SJean-Christophe Dubois 305f4427280SJean-Christophe Dubois s->dr = 0; 306f4427280SJean-Christophe Dubois s->gdir = 0; 307f4427280SJean-Christophe Dubois s->psr = 0; 308f4427280SJean-Christophe Dubois s->icr = 0; 309f4427280SJean-Christophe Dubois s->imr = 0; 310f4427280SJean-Christophe Dubois s->isr = 0; 311f4427280SJean-Christophe Dubois s->edge_sel = 0; 312f4427280SJean-Christophe Dubois 313f4427280SJean-Christophe Dubois imx_gpio_set_all_output_lines(s); 314f4427280SJean-Christophe Dubois imx_gpio_update_int(s); 315f4427280SJean-Christophe Dubois } 316f4427280SJean-Christophe Dubois 317f4427280SJean-Christophe Dubois static void imx_gpio_realize(DeviceState *dev, Error **errp) 318f4427280SJean-Christophe Dubois { 319f4427280SJean-Christophe Dubois IMXGPIOState *s = IMX_GPIO(dev); 320f4427280SJean-Christophe Dubois 321f4427280SJean-Christophe Dubois memory_region_init_io(&s->iomem, OBJECT(s), &imx_gpio_ops, s, 322f4427280SJean-Christophe Dubois TYPE_IMX_GPIO, IMX_GPIO_MEM_SIZE); 323f4427280SJean-Christophe Dubois 324f4427280SJean-Christophe Dubois qdev_init_gpio_in(DEVICE(s), imx_gpio_set, IMX_GPIO_PIN_COUNT); 325f4427280SJean-Christophe Dubois qdev_init_gpio_out(DEVICE(s), s->output, IMX_GPIO_PIN_COUNT); 326f4427280SJean-Christophe Dubois 327f1f7e4bfSJean-Christophe Dubois sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[0]); 328f1f7e4bfSJean-Christophe Dubois sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[1]); 329f4427280SJean-Christophe Dubois sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); 330f4427280SJean-Christophe Dubois } 331f4427280SJean-Christophe Dubois 332f4427280SJean-Christophe Dubois static void imx_gpio_class_init(ObjectClass *klass, void *data) 333f4427280SJean-Christophe Dubois { 334f4427280SJean-Christophe Dubois DeviceClass *dc = DEVICE_CLASS(klass); 335f4427280SJean-Christophe Dubois 336f4427280SJean-Christophe Dubois dc->realize = imx_gpio_realize; 337f4427280SJean-Christophe Dubois dc->reset = imx_gpio_reset; 338f4427280SJean-Christophe Dubois dc->props = imx_gpio_properties; 339f4427280SJean-Christophe Dubois dc->vmsd = &vmstate_imx_gpio; 340f4427280SJean-Christophe Dubois dc->desc = "i.MX GPIO controller"; 341f4427280SJean-Christophe Dubois } 342f4427280SJean-Christophe Dubois 343f4427280SJean-Christophe Dubois static const TypeInfo imx_gpio_info = { 344f4427280SJean-Christophe Dubois .name = TYPE_IMX_GPIO, 345f4427280SJean-Christophe Dubois .parent = TYPE_SYS_BUS_DEVICE, 346f4427280SJean-Christophe Dubois .instance_size = sizeof(IMXGPIOState), 347f4427280SJean-Christophe Dubois .class_init = imx_gpio_class_init, 348f4427280SJean-Christophe Dubois }; 349f4427280SJean-Christophe Dubois 350f4427280SJean-Christophe Dubois static void imx_gpio_register_types(void) 351f4427280SJean-Christophe Dubois { 352f4427280SJean-Christophe Dubois type_register_static(&imx_gpio_info); 353f4427280SJean-Christophe Dubois } 354f4427280SJean-Christophe Dubois 355f4427280SJean-Christophe Dubois type_init(imx_gpio_register_types) 356