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