qemu/hw/sensor/emc141x.c
<<
>>
Prefs
   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
  32struct 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
  44struct EMC141XClass {
  45    I2CSlaveClass parent_class;
  46    uint8_t model;
  47    unsigned sensors_count;
  48};
  49
  50#define TYPE_EMC141X "emc141x"
  51OBJECT_DECLARE_TYPE(EMC141XState, EMC141XClass, EMC141X)
  52
  53static 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
  76static 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
 101static 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
 155static 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
 187static 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
 199static 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
 215static 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
 227static const VMStateDescription vmstate_emc141x = {
 228    .name = "EMC141X",
 229    .version_id = 0,
 230    .minimum_version_id = 0,
 231    .fields = (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
 240static 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
 252static 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
 268static 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
 280static 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
 289static 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
 298static 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
 307static const TypeInfo emc1413_info = {
 308    .name          = "emc1413",
 309    .parent        = TYPE_EMC141X,
 310    .class_init    = emc1413_class_init,
 311};
 312
 313static const TypeInfo emc1414_info = {
 314    .name          = "emc1414",
 315    .parent        = TYPE_EMC141X,
 316    .class_init    = emc1414_class_init,
 317};
 318
 319static 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
 326type_init(emc141x_register_types)
 327