 e3d0814368
			
		
	
	
		e3d0814368
		
	
	
	
	
		
			
			Use device_class_set_legacy_reset() instead of opencoding an
assignment to DeviceClass::reset. This change was produced
with:
 spatch --macro-file scripts/cocci-macro-file.h \
    --sp-file scripts/coccinelle/device-reset.cocci \
    --keep-comments --smpl-spacing --in-place --dir hw
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20240830145812.1967042-8-peter.maydell@linaro.org
		
	
			
		
			
				
	
	
		
			460 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			460 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Aspeed ADC
 | |
|  *
 | |
|  * Copyright 2017-2021 IBM Corp.
 | |
|  *
 | |
|  * Andrew Jeffery <andrew@aj.id.au>
 | |
|  *
 | |
|  * SPDX-License-Identifier: GPL-2.0-or-later
 | |
|  */
 | |
| 
 | |
| #include "qemu/osdep.h"
 | |
| #include "qapi/error.h"
 | |
| #include "qemu/log.h"
 | |
| #include "hw/irq.h"
 | |
| #include "hw/qdev-properties.h"
 | |
| #include "migration/vmstate.h"
 | |
| #include "hw/adc/aspeed_adc.h"
 | |
| #include "trace.h"
 | |
| 
 | |
| #define ASPEED_ADC_MEMORY_REGION_SIZE           0x1000
 | |
| #define ASPEED_ADC_ENGINE_MEMORY_REGION_SIZE    0x100
 | |
| #define  ASPEED_ADC_ENGINE_CH_EN_MASK           0xffff0000
 | |
| #define   ASPEED_ADC_ENGINE_CH_EN(x)            ((BIT(x)) << 16)
 | |
| #define  ASPEED_ADC_ENGINE_INIT                 BIT(8)
 | |
| #define  ASPEED_ADC_ENGINE_AUTO_COMP            BIT(5)
 | |
| #define  ASPEED_ADC_ENGINE_COMP                 BIT(4)
 | |
| #define  ASPEED_ADC_ENGINE_MODE_MASK            0x0000000e
 | |
| #define   ASPEED_ADC_ENGINE_MODE_OFF            (0b000 << 1)
 | |
| #define   ASPEED_ADC_ENGINE_MODE_STANDBY        (0b001 << 1)
 | |
| #define   ASPEED_ADC_ENGINE_MODE_NORMAL         (0b111 << 1)
 | |
| #define  ASPEED_ADC_ENGINE_EN                   BIT(0)
 | |
| #define ASPEED_ADC_HYST_EN                      BIT(31)
 | |
| 
 | |
| #define ASPEED_ADC_L_MASK       ((1 << 10) - 1)
 | |
| #define ASPEED_ADC_L(x)         ((x) & ASPEED_ADC_L_MASK)
 | |
| #define ASPEED_ADC_H(x)         (((x) >> 16) & ASPEED_ADC_L_MASK)
 | |
| #define ASPEED_ADC_LH_MASK      (ASPEED_ADC_L_MASK << 16 | ASPEED_ADC_L_MASK)
 | |
| #define LOWER_CHANNEL_MASK      ((1 << 10) - 1)
 | |
| #define LOWER_CHANNEL_DATA(x)   ((x) & LOWER_CHANNEL_MASK)
 | |
| #define UPPER_CHANNEL_DATA(x)   (((x) >> 16) & LOWER_CHANNEL_MASK)
 | |
| 
 | |
| #define TO_REG(addr) (addr >> 2)
 | |
| 
 | |
| #define ENGINE_CONTROL              TO_REG(0x00)
 | |
| #define INTERRUPT_CONTROL           TO_REG(0x04)
 | |
| #define VGA_DETECT_CONTROL          TO_REG(0x08)
 | |
| #define CLOCK_CONTROL               TO_REG(0x0C)
 | |
| #define DATA_CHANNEL_1_AND_0        TO_REG(0x10)
 | |
| #define DATA_CHANNEL_7_AND_6        TO_REG(0x1C)
 | |
| #define DATA_CHANNEL_9_AND_8        TO_REG(0x20)
 | |
| #define DATA_CHANNEL_15_AND_14      TO_REG(0x2C)
 | |
| #define BOUNDS_CHANNEL_0            TO_REG(0x30)
 | |
| #define BOUNDS_CHANNEL_7            TO_REG(0x4C)
 | |
| #define BOUNDS_CHANNEL_8            TO_REG(0x50)
 | |
| #define BOUNDS_CHANNEL_15           TO_REG(0x6C)
 | |
| #define HYSTERESIS_CHANNEL_0        TO_REG(0x70)
 | |
| #define HYSTERESIS_CHANNEL_7        TO_REG(0x8C)
 | |
| #define HYSTERESIS_CHANNEL_8        TO_REG(0x90)
 | |
| #define HYSTERESIS_CHANNEL_15       TO_REG(0xAC)
 | |
| #define INTERRUPT_SOURCE            TO_REG(0xC0)
 | |
| #define COMPENSATING_AND_TRIMMING   TO_REG(0xC4)
 | |
| 
 | |
| static inline uint32_t update_channels(uint32_t current)
 | |
| {
 | |
|     return ((((current >> 16) & ASPEED_ADC_L_MASK) + 7) << 16) |
 | |
|         ((current + 5) & ASPEED_ADC_L_MASK);
 | |
| }
 | |
| 
 | |
| static bool breaks_threshold(AspeedADCEngineState *s, int reg)
 | |
| {
 | |
|     assert(reg >= DATA_CHANNEL_1_AND_0 &&
 | |
|            reg < DATA_CHANNEL_1_AND_0 + s->nr_channels / 2);
 | |
| 
 | |
|     int a_bounds_reg = BOUNDS_CHANNEL_0 + (reg - DATA_CHANNEL_1_AND_0) * 2;
 | |
|     int b_bounds_reg = a_bounds_reg + 1;
 | |
|     uint32_t a_and_b = s->regs[reg];
 | |
|     uint32_t a_bounds = s->regs[a_bounds_reg];
 | |
|     uint32_t b_bounds = s->regs[b_bounds_reg];
 | |
|     uint32_t a = ASPEED_ADC_L(a_and_b);
 | |
|     uint32_t b = ASPEED_ADC_H(a_and_b);
 | |
|     uint32_t a_lower = ASPEED_ADC_L(a_bounds);
 | |
|     uint32_t a_upper = ASPEED_ADC_H(a_bounds);
 | |
|     uint32_t b_lower = ASPEED_ADC_L(b_bounds);
 | |
|     uint32_t b_upper = ASPEED_ADC_H(b_bounds);
 | |
| 
 | |
|     return (a < a_lower || a > a_upper) ||
 | |
|            (b < b_lower || b > b_upper);
 | |
| }
 | |
| 
 | |
| static uint32_t read_channel_sample(AspeedADCEngineState *s, int reg)
 | |
| {
 | |
|     assert(reg >= DATA_CHANNEL_1_AND_0 &&
 | |
|            reg < DATA_CHANNEL_1_AND_0 + s->nr_channels / 2);
 | |
| 
 | |
|     /* Poor man's sampling */
 | |
|     uint32_t value = s->regs[reg];
 | |
|     s->regs[reg] = update_channels(s->regs[reg]);
 | |
| 
 | |
|     if (breaks_threshold(s, reg)) {
 | |
|         s->regs[INTERRUPT_CONTROL] |= BIT(reg - DATA_CHANNEL_1_AND_0);
 | |
|         qemu_irq_raise(s->irq);
 | |
|     }
 | |
| 
 | |
|     return value;
 | |
| }
 | |
| 
 | |
| static uint64_t aspeed_adc_engine_read(void *opaque, hwaddr addr,
 | |
|                                        unsigned int size)
 | |
| {
 | |
|     AspeedADCEngineState *s = ASPEED_ADC_ENGINE(opaque);
 | |
|     int reg = TO_REG(addr);
 | |
|     uint32_t value = 0;
 | |
| 
 | |
|     switch (reg) {
 | |
|     case BOUNDS_CHANNEL_8 ... BOUNDS_CHANNEL_15:
 | |
|         if (s->nr_channels <= 8) {
 | |
|             qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
 | |
|                           "bounds register %u invalid, only 0...7 valid\n",
 | |
|                           __func__, s->engine_id, reg - BOUNDS_CHANNEL_0);
 | |
|             break;
 | |
|         }
 | |
|         /* fallthrough */
 | |
|     case HYSTERESIS_CHANNEL_8 ... HYSTERESIS_CHANNEL_15:
 | |
|         if (s->nr_channels <= 8) {
 | |
|             qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
 | |
|                           "hysteresis register %u invalid, only 0...7 valid\n",
 | |
|                           __func__, s->engine_id, reg - HYSTERESIS_CHANNEL_0);
 | |
|             break;
 | |
|         }
 | |
|         /* fallthrough */
 | |
|     case BOUNDS_CHANNEL_0 ... BOUNDS_CHANNEL_7:
 | |
|     case HYSTERESIS_CHANNEL_0 ... HYSTERESIS_CHANNEL_7:
 | |
|     case ENGINE_CONTROL:
 | |
|     case INTERRUPT_CONTROL:
 | |
|     case VGA_DETECT_CONTROL:
 | |
|     case CLOCK_CONTROL:
 | |
|     case INTERRUPT_SOURCE:
 | |
|     case COMPENSATING_AND_TRIMMING:
 | |
|         value = s->regs[reg];
 | |
|         break;
 | |
|     case DATA_CHANNEL_9_AND_8 ... DATA_CHANNEL_15_AND_14:
 | |
|         if (s->nr_channels <= 8) {
 | |
|             qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
 | |
|                           "data register %u invalid, only 0...3 valid\n",
 | |
|                           __func__, s->engine_id, reg - DATA_CHANNEL_1_AND_0);
 | |
|             break;
 | |
|         }
 | |
|         /* fallthrough */
 | |
|     case DATA_CHANNEL_1_AND_0 ... DATA_CHANNEL_7_AND_6:
 | |
|         value = read_channel_sample(s, reg);
 | |
|         /* Allow 16-bit reads of the data registers */
 | |
|         if (addr & 0x2) {
 | |
|             assert(size == 2);
 | |
|             value >>= 16;
 | |
|         }
 | |
|         break;
 | |
|     default:
 | |
|         qemu_log_mask(LOG_UNIMP, "%s: engine[%u]: 0x%" HWADDR_PRIx "\n",
 | |
|                       __func__, s->engine_id, addr);
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     trace_aspeed_adc_engine_read(s->engine_id, addr, value);
 | |
|     return value;
 | |
| }
 | |
| 
 | |
| static void aspeed_adc_engine_write(void *opaque, hwaddr addr, uint64_t value,
 | |
|                                     unsigned int size)
 | |
| {
 | |
|     AspeedADCEngineState *s = ASPEED_ADC_ENGINE(opaque);
 | |
|     int reg = TO_REG(addr);
 | |
|     uint32_t init = 0;
 | |
| 
 | |
|     trace_aspeed_adc_engine_write(s->engine_id, addr, value);
 | |
| 
 | |
|     switch (reg) {
 | |
|     case ENGINE_CONTROL:
 | |
|         init = !!(value & ASPEED_ADC_ENGINE_EN);
 | |
|         init *= ASPEED_ADC_ENGINE_INIT;
 | |
| 
 | |
|         value &= ~ASPEED_ADC_ENGINE_INIT;
 | |
|         value |= init;
 | |
| 
 | |
|         value &= ~ASPEED_ADC_ENGINE_AUTO_COMP;
 | |
|         break;
 | |
|     case INTERRUPT_CONTROL:
 | |
|     case VGA_DETECT_CONTROL:
 | |
|     case CLOCK_CONTROL:
 | |
|         break;
 | |
|     case DATA_CHANNEL_9_AND_8 ... DATA_CHANNEL_15_AND_14:
 | |
|         if (s->nr_channels <= 8) {
 | |
|             qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
 | |
|                           "data register %u invalid, only 0...3 valid\n",
 | |
|                           __func__, s->engine_id, reg - DATA_CHANNEL_1_AND_0);
 | |
|             return;
 | |
|         }
 | |
|         /* fallthrough */
 | |
|     case BOUNDS_CHANNEL_8 ... BOUNDS_CHANNEL_15:
 | |
|         if (s->nr_channels <= 8) {
 | |
|             qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
 | |
|                           "bounds register %u invalid, only 0...7 valid\n",
 | |
|                           __func__, s->engine_id, reg - BOUNDS_CHANNEL_0);
 | |
|             return;
 | |
|         }
 | |
|         /* fallthrough */
 | |
|     case DATA_CHANNEL_1_AND_0 ... DATA_CHANNEL_7_AND_6:
 | |
|     case BOUNDS_CHANNEL_0 ... BOUNDS_CHANNEL_7:
 | |
|         value &= ASPEED_ADC_LH_MASK;
 | |
|         break;
 | |
|     case HYSTERESIS_CHANNEL_8 ... HYSTERESIS_CHANNEL_15:
 | |
|         if (s->nr_channels <= 8) {
 | |
|             qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
 | |
|                           "hysteresis register %u invalid, only 0...7 valid\n",
 | |
|                           __func__, s->engine_id, reg - HYSTERESIS_CHANNEL_0);
 | |
|             return;
 | |
|         }
 | |
|         /* fallthrough */
 | |
|     case HYSTERESIS_CHANNEL_0 ... HYSTERESIS_CHANNEL_7:
 | |
|         value &= (ASPEED_ADC_HYST_EN | ASPEED_ADC_LH_MASK);
 | |
|         break;
 | |
|     case INTERRUPT_SOURCE:
 | |
|         value &= 0xffff;
 | |
|         break;
 | |
|     case COMPENSATING_AND_TRIMMING:
 | |
|         value &= 0xf;
 | |
|         break;
 | |
|     default:
 | |
|         qemu_log_mask(LOG_UNIMP, "%s: engine[%u]: "
 | |
|                       "0x%" HWADDR_PRIx " 0x%" PRIx64 "\n",
 | |
|                       __func__, s->engine_id, addr, value);
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     s->regs[reg] = value;
 | |
| }
 | |
| 
 | |
| static const MemoryRegionOps aspeed_adc_engine_ops = {
 | |
|     .read = aspeed_adc_engine_read,
 | |
|     .write = aspeed_adc_engine_write,
 | |
|     .endianness = DEVICE_LITTLE_ENDIAN,
 | |
|     .valid = {
 | |
|         .min_access_size = 2,
 | |
|         .max_access_size = 4,
 | |
|         .unaligned = false,
 | |
|     },
 | |
| };
 | |
| 
 | |
| static const uint32_t aspeed_adc_resets[ASPEED_ADC_NR_REGS] = {
 | |
|     [ENGINE_CONTROL]     = 0x00000000,
 | |
|     [INTERRUPT_CONTROL]  = 0x00000000,
 | |
|     [VGA_DETECT_CONTROL] = 0x0000000f,
 | |
|     [CLOCK_CONTROL]      = 0x0000000f,
 | |
| };
 | |
| 
 | |
| static void aspeed_adc_engine_reset(DeviceState *dev)
 | |
| {
 | |
|     AspeedADCEngineState *s = ASPEED_ADC_ENGINE(dev);
 | |
| 
 | |
|     memcpy(s->regs, aspeed_adc_resets, sizeof(aspeed_adc_resets));
 | |
| }
 | |
| 
 | |
| static void aspeed_adc_engine_realize(DeviceState *dev, Error **errp)
 | |
| {
 | |
|     AspeedADCEngineState *s = ASPEED_ADC_ENGINE(dev);
 | |
|     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 | |
|     g_autofree char *name = g_strdup_printf(TYPE_ASPEED_ADC_ENGINE ".%d",
 | |
|                                             s->engine_id);
 | |
| 
 | |
|     assert(s->engine_id < 2);
 | |
| 
 | |
|     sysbus_init_irq(sbd, &s->irq);
 | |
| 
 | |
|     memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_adc_engine_ops, s, name,
 | |
|                           ASPEED_ADC_ENGINE_MEMORY_REGION_SIZE);
 | |
| 
 | |
|     sysbus_init_mmio(sbd, &s->mmio);
 | |
| }
 | |
| 
 | |
| static const VMStateDescription vmstate_aspeed_adc_engine = {
 | |
|     .name = TYPE_ASPEED_ADC,
 | |
|     .version_id = 1,
 | |
|     .minimum_version_id = 1,
 | |
|     .fields = (const VMStateField[]) {
 | |
|         VMSTATE_UINT32_ARRAY(regs, AspeedADCEngineState, ASPEED_ADC_NR_REGS),
 | |
|         VMSTATE_END_OF_LIST(),
 | |
|     }
 | |
| };
 | |
| 
 | |
| static Property aspeed_adc_engine_properties[] = {
 | |
|     DEFINE_PROP_UINT32("engine-id", AspeedADCEngineState, engine_id, 0),
 | |
|     DEFINE_PROP_UINT32("nr-channels", AspeedADCEngineState, nr_channels, 0),
 | |
|     DEFINE_PROP_END_OF_LIST(),
 | |
| };
 | |
| 
 | |
| static void aspeed_adc_engine_class_init(ObjectClass *klass, void *data)
 | |
| {
 | |
|     DeviceClass *dc = DEVICE_CLASS(klass);
 | |
| 
 | |
|     dc->realize = aspeed_adc_engine_realize;
 | |
|     device_class_set_legacy_reset(dc, aspeed_adc_engine_reset);
 | |
|     device_class_set_props(dc, aspeed_adc_engine_properties);
 | |
|     dc->desc = "Aspeed Analog-to-Digital Engine";
 | |
|     dc->vmsd = &vmstate_aspeed_adc_engine;
 | |
| }
 | |
| 
 | |
| static const TypeInfo aspeed_adc_engine_info = {
 | |
|     .name = TYPE_ASPEED_ADC_ENGINE,
 | |
|     .parent = TYPE_SYS_BUS_DEVICE,
 | |
|     .instance_size = sizeof(AspeedADCEngineState),
 | |
|     .class_init = aspeed_adc_engine_class_init,
 | |
| };
 | |
| 
 | |
| static void aspeed_adc_instance_init(Object *obj)
 | |
| {
 | |
|     AspeedADCState *s = ASPEED_ADC(obj);
 | |
|     AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(obj);
 | |
|     uint32_t nr_channels = ASPEED_ADC_NR_CHANNELS / aac->nr_engines;
 | |
| 
 | |
|     for (int i = 0; i < aac->nr_engines; i++) {
 | |
|         AspeedADCEngineState *engine = &s->engines[i];
 | |
|         object_initialize_child(obj, "engine[*]", engine,
 | |
|                                 TYPE_ASPEED_ADC_ENGINE);
 | |
|         qdev_prop_set_uint32(DEVICE(engine), "engine-id", i);
 | |
|         qdev_prop_set_uint32(DEVICE(engine), "nr-channels", nr_channels);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void aspeed_adc_set_irq(void *opaque, int n, int level)
 | |
| {
 | |
|     AspeedADCState *s = opaque;
 | |
|     AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(s);
 | |
|     uint32_t pending = 0;
 | |
| 
 | |
|     /* TODO: update Global IRQ status register on AST2600 (Need specs) */
 | |
|     for (int i = 0; i < aac->nr_engines; i++) {
 | |
|         uint32_t irq_status = s->engines[i].regs[INTERRUPT_CONTROL] & 0xFF;
 | |
|         pending |= irq_status << (i * 8);
 | |
|     }
 | |
| 
 | |
|     qemu_set_irq(s->irq, !!pending);
 | |
| }
 | |
| 
 | |
| static void aspeed_adc_realize(DeviceState *dev, Error **errp)
 | |
| {
 | |
|     AspeedADCState *s = ASPEED_ADC(dev);
 | |
|     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 | |
|     AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(dev);
 | |
| 
 | |
|     qdev_init_gpio_in_named_with_opaque(DEVICE(sbd), aspeed_adc_set_irq,
 | |
|                                         s, NULL, aac->nr_engines);
 | |
| 
 | |
|     sysbus_init_irq(sbd, &s->irq);
 | |
| 
 | |
|     memory_region_init(&s->mmio, OBJECT(s), TYPE_ASPEED_ADC,
 | |
|                        ASPEED_ADC_MEMORY_REGION_SIZE);
 | |
| 
 | |
|     sysbus_init_mmio(sbd, &s->mmio);
 | |
| 
 | |
|     for (int i = 0; i < aac->nr_engines; i++) {
 | |
|         Object *eng = OBJECT(&s->engines[i]);
 | |
| 
 | |
|         if (!sysbus_realize(SYS_BUS_DEVICE(eng), errp)) {
 | |
|             return;
 | |
|         }
 | |
|         sysbus_connect_irq(SYS_BUS_DEVICE(eng), 0,
 | |
|                            qdev_get_gpio_in(DEVICE(sbd), i));
 | |
|         memory_region_add_subregion(&s->mmio,
 | |
|                                     i * ASPEED_ADC_ENGINE_MEMORY_REGION_SIZE,
 | |
|                                     &s->engines[i].mmio);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void aspeed_adc_class_init(ObjectClass *klass, void *data)
 | |
| {
 | |
|     DeviceClass *dc = DEVICE_CLASS(klass);
 | |
|     AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
 | |
| 
 | |
|     dc->realize = aspeed_adc_realize;
 | |
|     dc->desc = "Aspeed Analog-to-Digital Converter";
 | |
|     aac->nr_engines = 1;
 | |
| }
 | |
| 
 | |
| static void aspeed_2600_adc_class_init(ObjectClass *klass, void *data)
 | |
| {
 | |
|     DeviceClass *dc = DEVICE_CLASS(klass);
 | |
|     AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
 | |
| 
 | |
|     dc->desc = "ASPEED 2600 ADC Controller";
 | |
|     aac->nr_engines = 2;
 | |
| }
 | |
| 
 | |
| static void aspeed_1030_adc_class_init(ObjectClass *klass, void *data)
 | |
| {
 | |
|     DeviceClass *dc = DEVICE_CLASS(klass);
 | |
|     AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
 | |
| 
 | |
|     dc->desc = "ASPEED 1030 ADC Controller";
 | |
|     aac->nr_engines = 2;
 | |
| }
 | |
| 
 | |
| static void aspeed_2700_adc_class_init(ObjectClass *klass, void *data)
 | |
| {
 | |
|     DeviceClass *dc = DEVICE_CLASS(klass);
 | |
|     AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
 | |
| 
 | |
|     dc->desc = "ASPEED 2700 ADC Controller";
 | |
|     aac->nr_engines = 2;
 | |
| }
 | |
| 
 | |
| static const TypeInfo aspeed_adc_info = {
 | |
|     .name = TYPE_ASPEED_ADC,
 | |
|     .parent = TYPE_SYS_BUS_DEVICE,
 | |
|     .instance_init = aspeed_adc_instance_init,
 | |
|     .instance_size = sizeof(AspeedADCState),
 | |
|     .class_init = aspeed_adc_class_init,
 | |
|     .class_size = sizeof(AspeedADCClass),
 | |
|     .abstract   = true,
 | |
| };
 | |
| 
 | |
| static const TypeInfo aspeed_2400_adc_info = {
 | |
|     .name = TYPE_ASPEED_2400_ADC,
 | |
|     .parent = TYPE_ASPEED_ADC,
 | |
| };
 | |
| 
 | |
| static const TypeInfo aspeed_2500_adc_info = {
 | |
|     .name = TYPE_ASPEED_2500_ADC,
 | |
|     .parent = TYPE_ASPEED_ADC,
 | |
| };
 | |
| 
 | |
| static const TypeInfo aspeed_2600_adc_info = {
 | |
|     .name = TYPE_ASPEED_2600_ADC,
 | |
|     .parent = TYPE_ASPEED_ADC,
 | |
|     .class_init = aspeed_2600_adc_class_init,
 | |
| };
 | |
| 
 | |
| static const TypeInfo aspeed_1030_adc_info = {
 | |
|     .name = TYPE_ASPEED_1030_ADC,
 | |
|     .parent = TYPE_ASPEED_ADC,
 | |
|     .class_init = aspeed_1030_adc_class_init, /* No change since AST2600 */
 | |
| };
 | |
| 
 | |
| static const TypeInfo aspeed_2700_adc_info = {
 | |
|     .name = TYPE_ASPEED_2700_ADC,
 | |
|     .parent = TYPE_ASPEED_ADC,
 | |
|     .class_init = aspeed_2700_adc_class_init,
 | |
| };
 | |
| 
 | |
| static void aspeed_adc_register_types(void)
 | |
| {
 | |
|     type_register_static(&aspeed_adc_engine_info);
 | |
|     type_register_static(&aspeed_adc_info);
 | |
|     type_register_static(&aspeed_2400_adc_info);
 | |
|     type_register_static(&aspeed_2500_adc_info);
 | |
|     type_register_static(&aspeed_2600_adc_info);
 | |
|     type_register_static(&aspeed_1030_adc_info);
 | |
|     type_register_static(&aspeed_2700_adc_info);
 | |
| }
 | |
| 
 | |
| type_init(aspeed_adc_register_types);
 |