qemu

Форк
0
/
ads7846.c 
186 строк · 4.6 Кб
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 = (const 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_any(NULL, &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)
187

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.