qemu

Форк
0
/
emc141x.c 
326 строк · 8.4 Кб
1
/*
2
 * SMSC EMC141X temperature sensor.
3
 *
4
 * Copyright (c) 2020 Bytedance Corporation
5
 * Written by John Wang <wangzhiqiang.bj@bytedance.com>
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License as
9
 * published by the Free Software Foundation; either version 2 or
10
 * (at your option) version 3 of the License.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License along
18
 * with this program; if not, see <http://www.gnu.org/licenses/>.
19
 */
20

21
#include "qemu/osdep.h"
22
#include "hw/i2c/i2c.h"
23
#include "migration/vmstate.h"
24
#include "qapi/error.h"
25
#include "qapi/visitor.h"
26
#include "qemu/module.h"
27
#include "qom/object.h"
28
#include "hw/sensor/emc141x_regs.h"
29

30
#define SENSORS_COUNT_MAX    4
31

32
struct EMC141XState {
33
    I2CSlave parent_obj;
34
    struct {
35
        uint8_t raw_temp_min;
36
        uint8_t raw_temp_current;
37
        uint8_t raw_temp_max;
38
    } sensor[SENSORS_COUNT_MAX];
39
    uint8_t len;
40
    uint8_t data;
41
    uint8_t pointer;
42
};
43

44
struct EMC141XClass {
45
    I2CSlaveClass parent_class;
46
    uint8_t model;
47
    unsigned sensors_count;
48
};
49

50
#define TYPE_EMC141X "emc141x"
51
OBJECT_DECLARE_TYPE(EMC141XState, EMC141XClass, EMC141X)
52

53
static void emc141x_get_temperature(Object *obj, Visitor *v, const char *name,
54
                                    void *opaque, Error **errp)
55
{
56
    EMC141XState *s = EMC141X(obj);
57
    EMC141XClass *sc = EMC141X_GET_CLASS(s);
58
    int64_t value;
59
    unsigned tempid;
60

61
    if (sscanf(name, "temperature%u", &tempid) != 1) {
62
        error_setg(errp, "error reading %s: %s", name, g_strerror(errno));
63
        return;
64
    }
65

66
    if (tempid >= sc->sensors_count) {
67
        error_setg(errp, "error reading %s", name);
68
        return;
69
    }
70

71
    value = s->sensor[tempid].raw_temp_current * 1000;
72

73
    visit_type_int(v, name, &value, errp);
74
}
75

76
static void emc141x_set_temperature(Object *obj, Visitor *v, const char *name,
77
                                    void *opaque, Error **errp)
78
{
79
    EMC141XState *s = EMC141X(obj);
80
    EMC141XClass *sc = EMC141X_GET_CLASS(s);
81
    int64_t temp;
82
    unsigned tempid;
83

84
    if (!visit_type_int(v, name, &temp, errp)) {
85
        return;
86
    }
87

88
    if (sscanf(name, "temperature%u", &tempid) != 1) {
89
        error_setg(errp, "error reading %s: %s", name, g_strerror(errno));
90
        return;
91
    }
92

93
    if (tempid >= sc->sensors_count) {
94
        error_setg(errp, "error reading %s", name);
95
        return;
96
    }
97

98
    s->sensor[tempid].raw_temp_current = temp / 1000;
99
}
100

101
static void emc141x_read(EMC141XState *s)
102
{
103
    EMC141XClass *sc = EMC141X_GET_CLASS(s);
104
    switch (s->pointer) {
105
    case EMC141X_DEVICE_ID:
106
        s->data = sc->model;
107
        break;
108
    case EMC141X_MANUFACTURER_ID:
109
        s->data = MANUFACTURER_ID;
110
        break;
111
    case EMC141X_REVISION:
112
        s->data = REVISION;
113
        break;
114
    case EMC141X_TEMP_HIGH0:
115
        s->data = s->sensor[0].raw_temp_current;
116
        break;
117
    case EMC141X_TEMP_HIGH1:
118
        s->data = s->sensor[1].raw_temp_current;
119
        break;
120
    case EMC141X_TEMP_HIGH2:
121
        s->data = s->sensor[2].raw_temp_current;
122
        break;
123
    case EMC141X_TEMP_HIGH3:
124
        s->data = s->sensor[3].raw_temp_current;
125
        break;
126
    case EMC141X_TEMP_MAX_HIGH0:
127
        s->data = s->sensor[0].raw_temp_max;
128
        break;
129
    case EMC141X_TEMP_MAX_HIGH1:
130
        s->data = s->sensor[1].raw_temp_max;
131
        break;
132
    case EMC141X_TEMP_MAX_HIGH2:
133
        s->data = s->sensor[2].raw_temp_max;
134
        break;
135
    case EMC141X_TEMP_MAX_HIGH3:
136
        s->data = s->sensor[3].raw_temp_max;
137
        break;
138
    case EMC141X_TEMP_MIN_HIGH0:
139
        s->data = s->sensor[0].raw_temp_min;
140
        break;
141
    case EMC141X_TEMP_MIN_HIGH1:
142
        s->data = s->sensor[1].raw_temp_min;
143
        break;
144
    case EMC141X_TEMP_MIN_HIGH2:
145
        s->data = s->sensor[2].raw_temp_min;
146
        break;
147
    case EMC141X_TEMP_MIN_HIGH3:
148
        s->data = s->sensor[3].raw_temp_min;
149
        break;
150
    default:
151
        s->data = 0;
152
    }
153
}
154

155
static void emc141x_write(EMC141XState *s)
156
{
157
    switch (s->pointer) {
158
    case EMC141X_TEMP_MAX_HIGH0:
159
        s->sensor[0].raw_temp_max = s->data;
160
        break;
161
    case EMC141X_TEMP_MAX_HIGH1:
162
        s->sensor[1].raw_temp_max = s->data;
163
        break;
164
    case EMC141X_TEMP_MAX_HIGH2:
165
        s->sensor[2].raw_temp_max = s->data;
166
        break;
167
    case EMC141X_TEMP_MAX_HIGH3:
168
        s->sensor[3].raw_temp_max = s->data;
169
        break;
170
    case EMC141X_TEMP_MIN_HIGH0:
171
        s->sensor[0].raw_temp_min = s->data;
172
        break;
173
    case EMC141X_TEMP_MIN_HIGH1:
174
        s->sensor[1].raw_temp_min = s->data;
175
        break;
176
    case EMC141X_TEMP_MIN_HIGH2:
177
        s->sensor[2].raw_temp_min = s->data;
178
        break;
179
    case EMC141X_TEMP_MIN_HIGH3:
180
        s->sensor[3].raw_temp_min = s->data;
181
        break;
182
    default:
183
        s->data = 0;
184
    }
185
}
186

187
static uint8_t emc141x_rx(I2CSlave *i2c)
188
{
189
    EMC141XState *s = EMC141X(i2c);
190

191
    if (s->len == 0) {
192
        s->len++;
193
        return s->data;
194
    } else {
195
        return 0xff;
196
    }
197
}
198

199
static int emc141x_tx(I2CSlave *i2c, uint8_t data)
200
{
201
    EMC141XState *s = EMC141X(i2c);
202

203
    if (s->len == 0) {
204
        /* first byte is the reg pointer */
205
        s->pointer = data;
206
        s->len++;
207
    } else if (s->len == 1) {
208
        s->data = data;
209
        emc141x_write(s);
210
    }
211

212
    return 0;
213
}
214

215
static int emc141x_event(I2CSlave *i2c, enum i2c_event event)
216
{
217
    EMC141XState *s = EMC141X(i2c);
218

219
    if (event == I2C_START_RECV) {
220
        emc141x_read(s);
221
    }
222

223
    s->len = 0;
224
    return 0;
225
}
226

227
static const VMStateDescription vmstate_emc141x = {
228
    .name = "EMC141X",
229
    .version_id = 0,
230
    .minimum_version_id = 0,
231
    .fields = (const VMStateField[]) {
232
        VMSTATE_UINT8(len, EMC141XState),
233
        VMSTATE_UINT8(data, EMC141XState),
234
        VMSTATE_UINT8(pointer, EMC141XState),
235
        VMSTATE_I2C_SLAVE(parent_obj, EMC141XState),
236
        VMSTATE_END_OF_LIST()
237
    }
238
};
239

240
static void emc141x_reset(DeviceState *dev)
241
{
242
    EMC141XState *s = EMC141X(dev);
243
    int i;
244

245
    for (i = 0; i < SENSORS_COUNT_MAX; i++) {
246
        s->sensor[i].raw_temp_max = 0x55;
247
    }
248
    s->pointer = 0;
249
    s->len = 0;
250
}
251

252
static void emc141x_initfn(Object *obj)
253
{
254
    object_property_add(obj, "temperature0", "int",
255
                        emc141x_get_temperature,
256
                        emc141x_set_temperature, NULL, NULL);
257
    object_property_add(obj, "temperature1", "int",
258
                        emc141x_get_temperature,
259
                        emc141x_set_temperature, NULL, NULL);
260
    object_property_add(obj, "temperature2", "int",
261
                        emc141x_get_temperature,
262
                        emc141x_set_temperature, NULL, NULL);
263
    object_property_add(obj, "temperature3", "int",
264
                        emc141x_get_temperature,
265
                        emc141x_set_temperature, NULL, NULL);
266
}
267

268
static void emc141x_class_init(ObjectClass *klass, void *data)
269
{
270
    DeviceClass *dc = DEVICE_CLASS(klass);
271
    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
272

273
    dc->reset = emc141x_reset;
274
    k->event = emc141x_event;
275
    k->recv = emc141x_rx;
276
    k->send = emc141x_tx;
277
    dc->vmsd = &vmstate_emc141x;
278
}
279

280
static void emc1413_class_init(ObjectClass *klass, void *data)
281
{
282
    EMC141XClass *ec = EMC141X_CLASS(klass);
283

284
    emc141x_class_init(klass, data);
285
    ec->model = EMC1413_DEVICE_ID;
286
    ec->sensors_count = 3;
287
}
288

289
static void emc1414_class_init(ObjectClass *klass, void *data)
290
{
291
    EMC141XClass *ec = EMC141X_CLASS(klass);
292

293
    emc141x_class_init(klass, data);
294
    ec->model = EMC1414_DEVICE_ID;
295
    ec->sensors_count = 4;
296
}
297

298
static const TypeInfo emc141x_info = {
299
    .name          = TYPE_EMC141X,
300
    .parent        = TYPE_I2C_SLAVE,
301
    .instance_size = sizeof(EMC141XState),
302
    .class_size    = sizeof(EMC141XClass),
303
    .instance_init = emc141x_initfn,
304
    .abstract      = true,
305
};
306

307
static const TypeInfo emc1413_info = {
308
    .name          = "emc1413",
309
    .parent        = TYPE_EMC141X,
310
    .class_init    = emc1413_class_init,
311
};
312

313
static const TypeInfo emc1414_info = {
314
    .name          = "emc1414",
315
    .parent        = TYPE_EMC141X,
316
    .class_init    = emc1414_class_init,
317
};
318

319
static void emc141x_register_types(void)
320
{
321
    type_register_static(&emc141x_info);
322
    type_register_static(&emc1413_info);
323
    type_register_static(&emc1414_info);
324
}
325

326
type_init(emc141x_register_types)
327

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

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

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

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