qemu/hw/sensor/dps310.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright 2017-2021 Joel Stanley <joel@jms.id.au>, IBM Corporation
   4 *
   5 * Infineon DPS310 temperature and humidity sensor
   6 *
   7 * https://www.infineon.com/cms/en/product/sensor/pressure-sensors/pressure-sensors-for-iot/dps310/
   8 */
   9
  10#include "qemu/osdep.h"
  11#include "qemu/log.h"
  12#include "hw/hw.h"
  13#include "hw/i2c/i2c.h"
  14#include "qapi/error.h"
  15#include "qapi/visitor.h"
  16#include "migration/vmstate.h"
  17
  18#define NUM_REGISTERS   0x33
  19
  20typedef struct DPS310State {
  21    /*< private >*/
  22    I2CSlave i2c;
  23
  24    /*< public >*/
  25    uint8_t regs[NUM_REGISTERS];
  26
  27    uint8_t len;
  28    uint8_t pointer;
  29
  30} DPS310State;
  31
  32#define TYPE_DPS310 "dps310"
  33#define DPS310(obj) OBJECT_CHECK(DPS310State, (obj), TYPE_DPS310)
  34
  35#define DPS310_PRS_B2           0x00
  36#define DPS310_PRS_B1           0x01
  37#define DPS310_PRS_B0           0x02
  38#define DPS310_TMP_B2           0x03
  39#define DPS310_TMP_B1           0x04
  40#define DPS310_TMP_B0           0x05
  41#define DPS310_PRS_CFG          0x06
  42#define DPS310_TMP_CFG          0x07
  43#define  DPS310_TMP_RATE_BITS   (0x70)
  44#define DPS310_MEAS_CFG         0x08
  45#define  DPS310_MEAS_CTRL_BITS  (0x07)
  46#define   DPS310_PRESSURE_EN    BIT(0)
  47#define   DPS310_TEMP_EN        BIT(1)
  48#define   DPS310_BACKGROUND     BIT(2)
  49#define  DPS310_PRS_RDY         BIT(4)
  50#define  DPS310_TMP_RDY         BIT(5)
  51#define  DPS310_SENSOR_RDY      BIT(6)
  52#define  DPS310_COEF_RDY        BIT(7)
  53#define DPS310_CFG_REG          0x09
  54#define DPS310_RESET            0x0c
  55#define  DPS310_RESET_MAGIC     (BIT(0) | BIT(3))
  56#define DPS310_COEF_BASE        0x10
  57#define DPS310_COEF_LAST        0x21
  58#define DPS310_COEF_SRC         0x28
  59
  60static void dps310_reset(DeviceState *dev)
  61{
  62    DPS310State *s = DPS310(dev);
  63
  64    static const uint8_t regs_reset_state[sizeof(s->regs)] = {
  65        0xfe, 0x2f, 0xee, 0x02, 0x69, 0xa6, 0x00, 0x80, 0xc7, 0x00, 0x00, 0x00,
  66        0x00, 0x10, 0x00, 0x00, 0x0e, 0x1e, 0xdd, 0x13, 0xca, 0x5f, 0x21, 0x52,
  67        0xf9, 0xc6, 0x04, 0xd1, 0xdb, 0x47, 0x00, 0x5b, 0xfb, 0x3a, 0x00, 0x00,
  68        0x20, 0x49, 0x4e, 0xa5, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  69        0x60, 0x15, 0x02
  70    };
  71
  72    memcpy(s->regs, regs_reset_state, sizeof(s->regs));
  73    s->pointer = 0;
  74
  75    /* TODO: assert these after some timeout ? */
  76    s->regs[DPS310_MEAS_CFG] = DPS310_COEF_RDY | DPS310_SENSOR_RDY
  77        | DPS310_TMP_RDY | DPS310_PRS_RDY;
  78}
  79
  80static uint8_t dps310_read(DPS310State *s, uint8_t reg)
  81{
  82    if (reg >= sizeof(s->regs)) {
  83        qemu_log_mask(LOG_GUEST_ERROR, "%s: register 0x%02x out of bounds\n",
  84                      __func__, s->pointer);
  85        return 0xFF;
  86    }
  87
  88    switch (reg) {
  89    case DPS310_PRS_B2:
  90    case DPS310_PRS_B1:
  91    case DPS310_PRS_B0:
  92    case DPS310_TMP_B2:
  93    case DPS310_TMP_B1:
  94    case DPS310_TMP_B0:
  95    case DPS310_PRS_CFG:
  96    case DPS310_TMP_CFG:
  97    case DPS310_MEAS_CFG:
  98    case DPS310_CFG_REG:
  99    case DPS310_COEF_BASE...DPS310_COEF_LAST:
 100    case DPS310_COEF_SRC:
 101    case 0x32: /* Undocumented register to indicate workaround not required */
 102        return s->regs[reg];
 103    default:
 104        qemu_log_mask(LOG_UNIMP, "%s: register 0x%02x unimplemented\n",
 105                      __func__, reg);
 106        return 0xFF;
 107    }
 108}
 109
 110static void dps310_write(DPS310State *s, uint8_t reg, uint8_t data)
 111{
 112    if (reg >= sizeof(s->regs)) {
 113        qemu_log_mask(LOG_GUEST_ERROR, "%s: register %d out of bounds\n",
 114                      __func__, s->pointer);
 115        return;
 116    }
 117
 118    switch (reg) {
 119    case DPS310_RESET:
 120        if (data == DPS310_RESET_MAGIC) {
 121            device_cold_reset(DEVICE(s));
 122        }
 123        break;
 124    case DPS310_PRS_CFG:
 125    case DPS310_TMP_CFG:
 126    case DPS310_MEAS_CFG:
 127    case DPS310_CFG_REG:
 128        s->regs[reg] = data;
 129        break;
 130    default:
 131        qemu_log_mask(LOG_UNIMP, "%s: register 0x%02x unimplemented\n",
 132                      __func__, reg);
 133        return;
 134    }
 135}
 136
 137static uint8_t dps310_rx(I2CSlave *i2c)
 138{
 139    DPS310State *s = DPS310(i2c);
 140
 141    if (s->len == 1) {
 142        return dps310_read(s, s->pointer++);
 143    } else {
 144        return 0xFF;
 145    }
 146}
 147
 148static int dps310_tx(I2CSlave *i2c, uint8_t data)
 149{
 150    DPS310State *s = DPS310(i2c);
 151
 152    if (s->len == 0) {
 153        /*
 154         * first byte is the register pointer for a read or write
 155         * operation
 156         */
 157        s->pointer = data;
 158        s->len++;
 159    } else if (s->len == 1) {
 160        dps310_write(s, s->pointer++, data);
 161    }
 162
 163    return 0;
 164}
 165
 166static int dps310_event(I2CSlave *i2c, enum i2c_event event)
 167{
 168    DPS310State *s = DPS310(i2c);
 169
 170    switch (event) {
 171    case I2C_START_SEND:
 172        s->pointer = 0xFF;
 173        s->len = 0;
 174        break;
 175    case I2C_START_RECV:
 176        if (s->len != 1) {
 177            qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid recv sequence\n",
 178                          __func__);
 179        }
 180        break;
 181    default:
 182        break;
 183    }
 184
 185    return 0;
 186}
 187
 188static const VMStateDescription vmstate_dps310 = {
 189    .name = "DPS310",
 190    .version_id = 0,
 191    .minimum_version_id = 0,
 192    .fields = (VMStateField[]) {
 193        VMSTATE_UINT8(len, DPS310State),
 194        VMSTATE_UINT8_ARRAY(regs, DPS310State, NUM_REGISTERS),
 195        VMSTATE_UINT8(pointer, DPS310State),
 196        VMSTATE_I2C_SLAVE(i2c, DPS310State),
 197        VMSTATE_END_OF_LIST()
 198    }
 199};
 200
 201static void dps310_class_init(ObjectClass *klass, void *data)
 202{
 203    DeviceClass *dc = DEVICE_CLASS(klass);
 204    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
 205
 206    k->event = dps310_event;
 207    k->recv = dps310_rx;
 208    k->send = dps310_tx;
 209    dc->reset = dps310_reset;
 210    dc->vmsd = &vmstate_dps310;
 211}
 212
 213static const TypeInfo dps310_info = {
 214    .name          = TYPE_DPS310,
 215    .parent        = TYPE_I2C_SLAVE,
 216    .instance_size = sizeof(DPS310State),
 217    .class_init    = dps310_class_init,
 218};
 219
 220static void dps310_register_types(void)
 221{
 222    type_register_static(&dps310_info);
 223}
 224
 225type_init(dps310_register_types)
 226