qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

stm32f2xx_adc.c (9339B)


      1 /*
      2  * STM32F2XX ADC
      3  *
      4  * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22  * THE SOFTWARE.
     23  */
     24 
     25 #include "qemu/osdep.h"
     26 #include "hw/sysbus.h"
     27 #include "migration/vmstate.h"
     28 #include "qemu/log.h"
     29 #include "qemu/module.h"
     30 #include "hw/adc/stm32f2xx_adc.h"
     31 
     32 #ifndef STM_ADC_ERR_DEBUG
     33 #define STM_ADC_ERR_DEBUG 0
     34 #endif
     35 
     36 #define DB_PRINT_L(lvl, fmt, args...) do { \
     37     if (STM_ADC_ERR_DEBUG >= lvl) { \
     38         qemu_log("%s: " fmt, __func__, ## args); \
     39     } \
     40 } while (0)
     41 
     42 #define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
     43 
     44 static void stm32f2xx_adc_reset(DeviceState *dev)
     45 {
     46     STM32F2XXADCState *s = STM32F2XX_ADC(dev);
     47 
     48     s->adc_sr = 0x00000000;
     49     s->adc_cr1 = 0x00000000;
     50     s->adc_cr2 = 0x00000000;
     51     s->adc_smpr1 = 0x00000000;
     52     s->adc_smpr2 = 0x00000000;
     53     s->adc_jofr[0] = 0x00000000;
     54     s->adc_jofr[1] = 0x00000000;
     55     s->adc_jofr[2] = 0x00000000;
     56     s->adc_jofr[3] = 0x00000000;
     57     s->adc_htr = 0x00000FFF;
     58     s->adc_ltr = 0x00000000;
     59     s->adc_sqr1 = 0x00000000;
     60     s->adc_sqr2 = 0x00000000;
     61     s->adc_sqr3 = 0x00000000;
     62     s->adc_jsqr = 0x00000000;
     63     s->adc_jdr[0] = 0x00000000;
     64     s->adc_jdr[1] = 0x00000000;
     65     s->adc_jdr[2] = 0x00000000;
     66     s->adc_jdr[3] = 0x00000000;
     67     s->adc_dr = 0x00000000;
     68 }
     69 
     70 static uint32_t stm32f2xx_adc_generate_value(STM32F2XXADCState *s)
     71 {
     72     /* Attempts to fake some ADC values */
     73     s->adc_dr = s->adc_dr + 7;
     74 
     75     switch ((s->adc_cr1 & ADC_CR1_RES) >> 24) {
     76     case 0:
     77         /* 12-bit */
     78         s->adc_dr &= 0xFFF;
     79         break;
     80     case 1:
     81         /* 10-bit */
     82         s->adc_dr &= 0x3FF;
     83         break;
     84     case 2:
     85         /* 8-bit */
     86         s->adc_dr &= 0xFF;
     87         break;
     88     default:
     89         /* 6-bit */
     90         s->adc_dr &= 0x3F;
     91     }
     92 
     93     if (s->adc_cr2 & ADC_CR2_ALIGN) {
     94         return (s->adc_dr << 1) & 0xFFF0;
     95     } else {
     96         return s->adc_dr;
     97     }
     98 }
     99 
    100 static uint64_t stm32f2xx_adc_read(void *opaque, hwaddr addr,
    101                                      unsigned int size)
    102 {
    103     STM32F2XXADCState *s = opaque;
    104 
    105     DB_PRINT("Address: 0x%" HWADDR_PRIx "\n", addr);
    106 
    107     if (addr >= ADC_COMMON_ADDRESS) {
    108         qemu_log_mask(LOG_UNIMP,
    109                       "%s: ADC Common Register Unsupported\n", __func__);
    110     }
    111 
    112     switch (addr) {
    113     case ADC_SR:
    114         return s->adc_sr;
    115     case ADC_CR1:
    116         return s->adc_cr1;
    117     case ADC_CR2:
    118         return s->adc_cr2 & 0xFFFFFFF;
    119     case ADC_SMPR1:
    120         return s->adc_smpr1;
    121     case ADC_SMPR2:
    122         return s->adc_smpr2;
    123     case ADC_JOFR1:
    124     case ADC_JOFR2:
    125     case ADC_JOFR3:
    126     case ADC_JOFR4:
    127         qemu_log_mask(LOG_UNIMP, "%s: " \
    128                       "Injection ADC is not implemented, the registers are " \
    129                       "included for compatibility\n", __func__);
    130         return s->adc_jofr[(addr - ADC_JOFR1) / 4];
    131     case ADC_HTR:
    132         return s->adc_htr;
    133     case ADC_LTR:
    134         return s->adc_ltr;
    135     case ADC_SQR1:
    136         return s->adc_sqr1;
    137     case ADC_SQR2:
    138         return s->adc_sqr2;
    139     case ADC_SQR3:
    140         return s->adc_sqr3;
    141     case ADC_JSQR:
    142         qemu_log_mask(LOG_UNIMP, "%s: " \
    143                       "Injection ADC is not implemented, the registers are " \
    144                       "included for compatibility\n", __func__);
    145         return s->adc_jsqr;
    146     case ADC_JDR1:
    147     case ADC_JDR2:
    148     case ADC_JDR3:
    149     case ADC_JDR4:
    150         qemu_log_mask(LOG_UNIMP, "%s: " \
    151                       "Injection ADC is not implemented, the registers are " \
    152                       "included for compatibility\n", __func__);
    153         return s->adc_jdr[(addr - ADC_JDR1) / 4] -
    154                s->adc_jofr[(addr - ADC_JDR1) / 4];
    155     case ADC_DR:
    156         if ((s->adc_cr2 & ADC_CR2_ADON) && (s->adc_cr2 & ADC_CR2_SWSTART)) {
    157             s->adc_cr2 ^= ADC_CR2_SWSTART;
    158             return stm32f2xx_adc_generate_value(s);
    159         } else {
    160             return 0;
    161         }
    162     default:
    163         qemu_log_mask(LOG_GUEST_ERROR,
    164                       "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
    165     }
    166 
    167     return 0;
    168 }
    169 
    170 static void stm32f2xx_adc_write(void *opaque, hwaddr addr,
    171                        uint64_t val64, unsigned int size)
    172 {
    173     STM32F2XXADCState *s = opaque;
    174     uint32_t value = (uint32_t) val64;
    175 
    176     DB_PRINT("Address: 0x%" HWADDR_PRIx ", Value: 0x%x\n",
    177              addr, value);
    178 
    179     if (addr >= 0x100) {
    180         qemu_log_mask(LOG_UNIMP,
    181                       "%s: ADC Common Register Unsupported\n", __func__);
    182     }
    183 
    184     switch (addr) {
    185     case ADC_SR:
    186         s->adc_sr &= (value & 0x3F);
    187         break;
    188     case ADC_CR1:
    189         s->adc_cr1 = value;
    190         break;
    191     case ADC_CR2:
    192         s->adc_cr2 = value;
    193         break;
    194     case ADC_SMPR1:
    195         s->adc_smpr1 = value;
    196         break;
    197     case ADC_SMPR2:
    198         s->adc_smpr2 = value;
    199         break;
    200     case ADC_JOFR1:
    201     case ADC_JOFR2:
    202     case ADC_JOFR3:
    203     case ADC_JOFR4:
    204         s->adc_jofr[(addr - ADC_JOFR1) / 4] = (value & 0xFFF);
    205         qemu_log_mask(LOG_UNIMP, "%s: " \
    206                       "Injection ADC is not implemented, the registers are " \
    207                       "included for compatibility\n", __func__);
    208         break;
    209     case ADC_HTR:
    210         s->adc_htr = value;
    211         break;
    212     case ADC_LTR:
    213         s->adc_ltr = value;
    214         break;
    215     case ADC_SQR1:
    216         s->adc_sqr1 = value;
    217         break;
    218     case ADC_SQR2:
    219         s->adc_sqr2 = value;
    220         break;
    221     case ADC_SQR3:
    222         s->adc_sqr3 = value;
    223         break;
    224     case ADC_JSQR:
    225         s->adc_jsqr = value;
    226         qemu_log_mask(LOG_UNIMP, "%s: " \
    227                       "Injection ADC is not implemented, the registers are " \
    228                       "included for compatibility\n", __func__);
    229         break;
    230     case ADC_JDR1:
    231     case ADC_JDR2:
    232     case ADC_JDR3:
    233     case ADC_JDR4:
    234         s->adc_jdr[(addr - ADC_JDR1) / 4] = value;
    235         qemu_log_mask(LOG_UNIMP, "%s: " \
    236                       "Injection ADC is not implemented, the registers are " \
    237                       "included for compatibility\n", __func__);
    238         break;
    239     default:
    240         qemu_log_mask(LOG_GUEST_ERROR,
    241                       "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
    242     }
    243 }
    244 
    245 static const MemoryRegionOps stm32f2xx_adc_ops = {
    246     .read = stm32f2xx_adc_read,
    247     .write = stm32f2xx_adc_write,
    248     .endianness = DEVICE_NATIVE_ENDIAN,
    249     .impl.min_access_size = 4,
    250     .impl.max_access_size = 4,
    251 };
    252 
    253 static const VMStateDescription vmstate_stm32f2xx_adc = {
    254     .name = TYPE_STM32F2XX_ADC,
    255     .version_id = 1,
    256     .minimum_version_id = 1,
    257     .fields = (VMStateField[]) {
    258         VMSTATE_UINT32(adc_sr, STM32F2XXADCState),
    259         VMSTATE_UINT32(adc_cr1, STM32F2XXADCState),
    260         VMSTATE_UINT32(adc_cr2, STM32F2XXADCState),
    261         VMSTATE_UINT32(adc_smpr1, STM32F2XXADCState),
    262         VMSTATE_UINT32(adc_smpr2, STM32F2XXADCState),
    263         VMSTATE_UINT32_ARRAY(adc_jofr, STM32F2XXADCState, 4),
    264         VMSTATE_UINT32(adc_htr, STM32F2XXADCState),
    265         VMSTATE_UINT32(adc_ltr, STM32F2XXADCState),
    266         VMSTATE_UINT32(adc_sqr1, STM32F2XXADCState),
    267         VMSTATE_UINT32(adc_sqr2, STM32F2XXADCState),
    268         VMSTATE_UINT32(adc_sqr3, STM32F2XXADCState),
    269         VMSTATE_UINT32(adc_jsqr, STM32F2XXADCState),
    270         VMSTATE_UINT32_ARRAY(adc_jdr, STM32F2XXADCState, 4),
    271         VMSTATE_UINT32(adc_dr, STM32F2XXADCState),
    272         VMSTATE_END_OF_LIST()
    273     }
    274 };
    275 
    276 static void stm32f2xx_adc_init(Object *obj)
    277 {
    278     STM32F2XXADCState *s = STM32F2XX_ADC(obj);
    279 
    280     sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
    281 
    282     memory_region_init_io(&s->mmio, obj, &stm32f2xx_adc_ops, s,
    283                           TYPE_STM32F2XX_ADC, 0x100);
    284     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
    285 }
    286 
    287 static void stm32f2xx_adc_class_init(ObjectClass *klass, void *data)
    288 {
    289     DeviceClass *dc = DEVICE_CLASS(klass);
    290 
    291     dc->reset = stm32f2xx_adc_reset;
    292     dc->vmsd = &vmstate_stm32f2xx_adc;
    293 }
    294 
    295 static const TypeInfo stm32f2xx_adc_info = {
    296     .name          = TYPE_STM32F2XX_ADC,
    297     .parent        = TYPE_SYS_BUS_DEVICE,
    298     .instance_size = sizeof(STM32F2XXADCState),
    299     .instance_init = stm32f2xx_adc_init,
    300     .class_init    = stm32f2xx_adc_class_init,
    301 };
    302 
    303 static void stm32f2xx_adc_register_types(void)
    304 {
    305     type_register_static(&stm32f2xx_adc_info);
    306 }
    307 
    308 type_init(stm32f2xx_adc_register_types)