qemu

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

ads7846.c (4626B)


      1 /*
      2  * TI ADS7846 / TSC2046 chip emulation.
      3  *
      4  * Copyright (c) 2006 Openedhand Ltd.
      5  * Written by Andrzej Zaborowski <balrog@zabor.org>
      6  *
      7  * This code is licensed under the GNU GPL v2.
      8  *
      9  * Contributions after 2012-01-13 are licensed under the terms of the
     10  * GNU GPL, version 2 or (at your option) any later version.
     11  */
     12 
     13 #include "qemu/osdep.h"
     14 #include "hw/irq.h"
     15 #include "hw/ssi/ssi.h"
     16 #include "migration/vmstate.h"
     17 #include "qemu/module.h"
     18 #include "ui/console.h"
     19 #include "qom/object.h"
     20 
     21 struct ADS7846State {
     22     SSIPeripheral ssidev;
     23     qemu_irq interrupt;
     24 
     25     int input[8];
     26     int pressure;
     27     int noise;
     28 
     29     int cycle;
     30     int output;
     31 };
     32 
     33 #define TYPE_ADS7846 "ads7846"
     34 OBJECT_DECLARE_SIMPLE_TYPE(ADS7846State, ADS7846)
     35 
     36 /* Control-byte bitfields */
     37 #define CB_PD0		(1 << 0)
     38 #define CB_PD1		(1 << 1)
     39 #define CB_SER		(1 << 2)
     40 #define CB_MODE		(1 << 3)
     41 #define CB_A0		(1 << 4)
     42 #define CB_A1		(1 << 5)
     43 #define CB_A2		(1 << 6)
     44 #define CB_START	(1 << 7)
     45 
     46 #define X_AXIS_DMAX	3470
     47 #define X_AXIS_MIN	290
     48 #define Y_AXIS_DMAX	3450
     49 #define Y_AXIS_MIN	200
     50 
     51 #define ADS_VBAT	2000
     52 #define ADS_VAUX	2000
     53 #define ADS_TEMP0	2000
     54 #define ADS_TEMP1	3000
     55 #define ADS_XPOS(x, y)	(X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15))
     56 #define ADS_YPOS(x, y)	(Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15))
     57 #define ADS_Z1POS(x, y)	600
     58 #define ADS_Z2POS(x, y)	(600 + 6000 / ADS_XPOS(x, y))
     59 
     60 static void ads7846_int_update(ADS7846State *s)
     61 {
     62     if (s->interrupt)
     63         qemu_set_irq(s->interrupt, s->pressure == 0);
     64 }
     65 
     66 static uint32_t ads7846_transfer(SSIPeripheral *dev, uint32_t value)
     67 {
     68     ADS7846State *s = ADS7846(dev);
     69 
     70     switch (s->cycle ++) {
     71     case 0:
     72         if (!(value & CB_START)) {
     73             s->cycle = 0;
     74             break;
     75         }
     76 
     77         s->output = s->input[(value >> 4) & 7];
     78 
     79         /* Imitate the ADC noise, some drivers expect this.  */
     80         s->noise = (s->noise + 3) & 7;
     81         switch ((value >> 4) & 7) {
     82         case 1: s->output += s->noise ^ 2; break;
     83         case 3: s->output += s->noise ^ 0; break;
     84         case 4: s->output += s->noise ^ 7; break;
     85         case 5: s->output += s->noise ^ 5; break;
     86         }
     87 
     88         if (value & CB_MODE)
     89             s->output >>= 4;	/* 8 bits instead of 12 */
     90 
     91         break;
     92     case 1:
     93         s->cycle = 0;
     94         break;
     95     }
     96     return s->output;
     97 }
     98 
     99 static void ads7846_ts_event(void *opaque,
    100                 int x, int y, int z, int buttons_state)
    101 {
    102     ADS7846State *s = opaque;
    103 
    104     if (buttons_state) {
    105         x = 0x7fff - x;
    106         s->input[1] = ADS_XPOS(x, y);
    107         s->input[3] = ADS_Z1POS(x, y);
    108         s->input[4] = ADS_Z2POS(x, y);
    109         s->input[5] = ADS_YPOS(x, y);
    110     }
    111 
    112     if (s->pressure == !buttons_state) {
    113         s->pressure = !!buttons_state;
    114 
    115         ads7846_int_update(s);
    116     }
    117 }
    118 
    119 static int ads7856_post_load(void *opaque, int version_id)
    120 {
    121     ADS7846State *s = opaque;
    122 
    123     s->pressure = 0;
    124     ads7846_int_update(s);
    125     return 0;
    126 }
    127 
    128 static const VMStateDescription vmstate_ads7846 = {
    129     .name = "ads7846",
    130     .version_id = 1,
    131     .minimum_version_id = 1,
    132     .post_load = ads7856_post_load,
    133     .fields = (VMStateField[]) {
    134         VMSTATE_SSI_PERIPHERAL(ssidev, ADS7846State),
    135         VMSTATE_INT32_ARRAY(input, ADS7846State, 8),
    136         VMSTATE_INT32(noise, ADS7846State),
    137         VMSTATE_INT32(cycle, ADS7846State),
    138         VMSTATE_INT32(output, ADS7846State),
    139         VMSTATE_END_OF_LIST()
    140     }
    141 };
    142 
    143 static void ads7846_realize(SSIPeripheral *d, Error **errp)
    144 {
    145     DeviceState *dev = DEVICE(d);
    146     ADS7846State *s = ADS7846(d);
    147 
    148     qdev_init_gpio_out(dev, &s->interrupt, 1);
    149 
    150     s->input[0] = ADS_TEMP0;	/* TEMP0 */
    151     s->input[2] = ADS_VBAT;	/* VBAT */
    152     s->input[6] = ADS_VAUX;	/* VAUX */
    153     s->input[7] = ADS_TEMP1;	/* TEMP1 */
    154 
    155     /* We want absolute coordinates */
    156     qemu_add_mouse_event_handler(ads7846_ts_event, s, 1,
    157                     "QEMU ADS7846-driven Touchscreen");
    158 
    159     ads7846_int_update(s);
    160 
    161     vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_ads7846, s);
    162 }
    163 
    164 static void ads7846_class_init(ObjectClass *klass, void *data)
    165 {
    166     DeviceClass *dc = DEVICE_CLASS(klass);
    167     SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
    168 
    169     k->realize = ads7846_realize;
    170     k->transfer = ads7846_transfer;
    171     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
    172 }
    173 
    174 static const TypeInfo ads7846_info = {
    175     .name          = TYPE_ADS7846,
    176     .parent        = TYPE_SSI_PERIPHERAL,
    177     .instance_size = sizeof(ADS7846State),
    178     .class_init    = ads7846_class_init,
    179 };
    180 
    181 static void ads7846_register_types(void)
    182 {
    183     type_register_static(&ads7846_info);
    184 }
    185 
    186 type_init(ads7846_register_types)