xref: /openbmc/qemu/hw/sensor/dps310.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
146560cb1SJoel Stanley // SPDX-License-Identifier: GPL-2.0-or-later
246560cb1SJoel Stanley /*
346560cb1SJoel Stanley  * Copyright 2017-2021 Joel Stanley <joel@jms.id.au>, IBM Corporation
446560cb1SJoel Stanley  *
546560cb1SJoel Stanley  * Infineon DPS310 temperature and humidity sensor
646560cb1SJoel Stanley  *
746560cb1SJoel Stanley  * https://www.infineon.com/cms/en/product/sensor/pressure-sensors/pressure-sensors-for-iot/dps310/
846560cb1SJoel Stanley  */
946560cb1SJoel Stanley 
1046560cb1SJoel Stanley #include "qemu/osdep.h"
1146560cb1SJoel Stanley #include "qemu/log.h"
1246560cb1SJoel Stanley #include "hw/i2c/i2c.h"
1346560cb1SJoel Stanley #include "qapi/error.h"
1446560cb1SJoel Stanley #include "qapi/visitor.h"
1546560cb1SJoel Stanley #include "migration/vmstate.h"
1646560cb1SJoel Stanley 
1746560cb1SJoel Stanley #define NUM_REGISTERS   0x33
1846560cb1SJoel Stanley 
1946560cb1SJoel Stanley typedef struct DPS310State {
2046560cb1SJoel Stanley     /*< private >*/
2146560cb1SJoel Stanley     I2CSlave i2c;
2246560cb1SJoel Stanley 
2346560cb1SJoel Stanley     /*< public >*/
2446560cb1SJoel Stanley     uint8_t regs[NUM_REGISTERS];
2546560cb1SJoel Stanley 
2646560cb1SJoel Stanley     uint8_t len;
2746560cb1SJoel Stanley     uint8_t pointer;
2846560cb1SJoel Stanley 
2946560cb1SJoel Stanley } DPS310State;
3046560cb1SJoel Stanley 
3146560cb1SJoel Stanley #define TYPE_DPS310 "dps310"
3246560cb1SJoel Stanley #define DPS310(obj) OBJECT_CHECK(DPS310State, (obj), TYPE_DPS310)
3346560cb1SJoel Stanley 
3446560cb1SJoel Stanley #define DPS310_PRS_B2           0x00
3546560cb1SJoel Stanley #define DPS310_PRS_B1           0x01
3646560cb1SJoel Stanley #define DPS310_PRS_B0           0x02
3746560cb1SJoel Stanley #define DPS310_TMP_B2           0x03
3846560cb1SJoel Stanley #define DPS310_TMP_B1           0x04
3946560cb1SJoel Stanley #define DPS310_TMP_B0           0x05
4046560cb1SJoel Stanley #define DPS310_PRS_CFG          0x06
4146560cb1SJoel Stanley #define DPS310_TMP_CFG          0x07
4246560cb1SJoel Stanley #define  DPS310_TMP_RATE_BITS   (0x70)
4346560cb1SJoel Stanley #define DPS310_MEAS_CFG         0x08
4446560cb1SJoel Stanley #define  DPS310_MEAS_CTRL_BITS  (0x07)
4546560cb1SJoel Stanley #define   DPS310_PRESSURE_EN    BIT(0)
4646560cb1SJoel Stanley #define   DPS310_TEMP_EN        BIT(1)
4746560cb1SJoel Stanley #define   DPS310_BACKGROUND     BIT(2)
4846560cb1SJoel Stanley #define  DPS310_PRS_RDY         BIT(4)
4946560cb1SJoel Stanley #define  DPS310_TMP_RDY         BIT(5)
5046560cb1SJoel Stanley #define  DPS310_SENSOR_RDY      BIT(6)
5146560cb1SJoel Stanley #define  DPS310_COEF_RDY        BIT(7)
5246560cb1SJoel Stanley #define DPS310_CFG_REG          0x09
5346560cb1SJoel Stanley #define DPS310_RESET            0x0c
5446560cb1SJoel Stanley #define  DPS310_RESET_MAGIC     (BIT(0) | BIT(3))
5546560cb1SJoel Stanley #define DPS310_COEF_BASE        0x10
5646560cb1SJoel Stanley #define DPS310_COEF_LAST        0x21
5746560cb1SJoel Stanley #define DPS310_COEF_SRC         0x28
5846560cb1SJoel Stanley 
dps310_reset(DeviceState * dev)5946560cb1SJoel Stanley static void dps310_reset(DeviceState *dev)
6046560cb1SJoel Stanley {
6146560cb1SJoel Stanley     DPS310State *s = DPS310(dev);
6246560cb1SJoel Stanley 
6346560cb1SJoel Stanley     static const uint8_t regs_reset_state[sizeof(s->regs)] = {
6446560cb1SJoel Stanley         0xfe, 0x2f, 0xee, 0x02, 0x69, 0xa6, 0x00, 0x80, 0xc7, 0x00, 0x00, 0x00,
6546560cb1SJoel Stanley         0x00, 0x10, 0x00, 0x00, 0x0e, 0x1e, 0xdd, 0x13, 0xca, 0x5f, 0x21, 0x52,
6646560cb1SJoel Stanley         0xf9, 0xc6, 0x04, 0xd1, 0xdb, 0x47, 0x00, 0x5b, 0xfb, 0x3a, 0x00, 0x00,
6746560cb1SJoel Stanley         0x20, 0x49, 0x4e, 0xa5, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6846560cb1SJoel Stanley         0x60, 0x15, 0x02
6946560cb1SJoel Stanley     };
7046560cb1SJoel Stanley 
7146560cb1SJoel Stanley     memcpy(s->regs, regs_reset_state, sizeof(s->regs));
7246560cb1SJoel Stanley     s->pointer = 0;
7346560cb1SJoel Stanley 
7446560cb1SJoel Stanley     /* TODO: assert these after some timeout ? */
7546560cb1SJoel Stanley     s->regs[DPS310_MEAS_CFG] = DPS310_COEF_RDY | DPS310_SENSOR_RDY
7646560cb1SJoel Stanley         | DPS310_TMP_RDY | DPS310_PRS_RDY;
7746560cb1SJoel Stanley }
7846560cb1SJoel Stanley 
dps310_read(DPS310State * s,uint8_t reg)7946560cb1SJoel Stanley static uint8_t dps310_read(DPS310State *s, uint8_t reg)
8046560cb1SJoel Stanley {
8146560cb1SJoel Stanley     if (reg >= sizeof(s->regs)) {
8246560cb1SJoel Stanley         qemu_log_mask(LOG_GUEST_ERROR, "%s: register 0x%02x out of bounds\n",
8346560cb1SJoel Stanley                       __func__, s->pointer);
8446560cb1SJoel Stanley         return 0xFF;
8546560cb1SJoel Stanley     }
8646560cb1SJoel Stanley 
8746560cb1SJoel Stanley     switch (reg) {
8846560cb1SJoel Stanley     case DPS310_PRS_B2:
8946560cb1SJoel Stanley     case DPS310_PRS_B1:
9046560cb1SJoel Stanley     case DPS310_PRS_B0:
9146560cb1SJoel Stanley     case DPS310_TMP_B2:
9246560cb1SJoel Stanley     case DPS310_TMP_B1:
9346560cb1SJoel Stanley     case DPS310_TMP_B0:
9446560cb1SJoel Stanley     case DPS310_PRS_CFG:
9546560cb1SJoel Stanley     case DPS310_TMP_CFG:
9646560cb1SJoel Stanley     case DPS310_MEAS_CFG:
9746560cb1SJoel Stanley     case DPS310_CFG_REG:
9846560cb1SJoel Stanley     case DPS310_COEF_BASE...DPS310_COEF_LAST:
9946560cb1SJoel Stanley     case DPS310_COEF_SRC:
10046560cb1SJoel Stanley     case 0x32: /* Undocumented register to indicate workaround not required */
10146560cb1SJoel Stanley         return s->regs[reg];
10246560cb1SJoel Stanley     default:
10346560cb1SJoel Stanley         qemu_log_mask(LOG_UNIMP, "%s: register 0x%02x unimplemented\n",
10446560cb1SJoel Stanley                       __func__, reg);
10546560cb1SJoel Stanley         return 0xFF;
10646560cb1SJoel Stanley     }
10746560cb1SJoel Stanley }
10846560cb1SJoel Stanley 
dps310_write(DPS310State * s,uint8_t reg,uint8_t data)10946560cb1SJoel Stanley static void dps310_write(DPS310State *s, uint8_t reg, uint8_t data)
11046560cb1SJoel Stanley {
11146560cb1SJoel Stanley     if (reg >= sizeof(s->regs)) {
11246560cb1SJoel Stanley         qemu_log_mask(LOG_GUEST_ERROR, "%s: register %d out of bounds\n",
11346560cb1SJoel Stanley                       __func__, s->pointer);
11446560cb1SJoel Stanley         return;
11546560cb1SJoel Stanley     }
11646560cb1SJoel Stanley 
11746560cb1SJoel Stanley     switch (reg) {
11846560cb1SJoel Stanley     case DPS310_RESET:
11946560cb1SJoel Stanley         if (data == DPS310_RESET_MAGIC) {
12046560cb1SJoel Stanley             device_cold_reset(DEVICE(s));
12146560cb1SJoel Stanley         }
12246560cb1SJoel Stanley         break;
12346560cb1SJoel Stanley     case DPS310_PRS_CFG:
12446560cb1SJoel Stanley     case DPS310_TMP_CFG:
12546560cb1SJoel Stanley     case DPS310_MEAS_CFG:
12646560cb1SJoel Stanley     case DPS310_CFG_REG:
12746560cb1SJoel Stanley         s->regs[reg] = data;
12846560cb1SJoel Stanley         break;
12946560cb1SJoel Stanley     default:
13046560cb1SJoel Stanley         qemu_log_mask(LOG_UNIMP, "%s: register 0x%02x unimplemented\n",
13146560cb1SJoel Stanley                       __func__, reg);
13246560cb1SJoel Stanley         return;
13346560cb1SJoel Stanley     }
13446560cb1SJoel Stanley }
13546560cb1SJoel Stanley 
dps310_rx(I2CSlave * i2c)13646560cb1SJoel Stanley static uint8_t dps310_rx(I2CSlave *i2c)
13746560cb1SJoel Stanley {
13846560cb1SJoel Stanley     DPS310State *s = DPS310(i2c);
13946560cb1SJoel Stanley 
14046560cb1SJoel Stanley     if (s->len == 1) {
14146560cb1SJoel Stanley         return dps310_read(s, s->pointer++);
14246560cb1SJoel Stanley     } else {
14346560cb1SJoel Stanley         return 0xFF;
14446560cb1SJoel Stanley     }
14546560cb1SJoel Stanley }
14646560cb1SJoel Stanley 
dps310_tx(I2CSlave * i2c,uint8_t data)14746560cb1SJoel Stanley static int dps310_tx(I2CSlave *i2c, uint8_t data)
14846560cb1SJoel Stanley {
14946560cb1SJoel Stanley     DPS310State *s = DPS310(i2c);
15046560cb1SJoel Stanley 
15146560cb1SJoel Stanley     if (s->len == 0) {
15246560cb1SJoel Stanley         /*
15346560cb1SJoel Stanley          * first byte is the register pointer for a read or write
15446560cb1SJoel Stanley          * operation
15546560cb1SJoel Stanley          */
15646560cb1SJoel Stanley         s->pointer = data;
15746560cb1SJoel Stanley         s->len++;
15846560cb1SJoel Stanley     } else if (s->len == 1) {
15946560cb1SJoel Stanley         dps310_write(s, s->pointer++, data);
16046560cb1SJoel Stanley     }
16146560cb1SJoel Stanley 
16246560cb1SJoel Stanley     return 0;
16346560cb1SJoel Stanley }
16446560cb1SJoel Stanley 
dps310_event(I2CSlave * i2c,enum i2c_event event)16546560cb1SJoel Stanley static int dps310_event(I2CSlave *i2c, enum i2c_event event)
16646560cb1SJoel Stanley {
16746560cb1SJoel Stanley     DPS310State *s = DPS310(i2c);
16846560cb1SJoel Stanley 
16946560cb1SJoel Stanley     switch (event) {
17046560cb1SJoel Stanley     case I2C_START_SEND:
17146560cb1SJoel Stanley         s->pointer = 0xFF;
17246560cb1SJoel Stanley         s->len = 0;
17346560cb1SJoel Stanley         break;
17446560cb1SJoel Stanley     case I2C_START_RECV:
17546560cb1SJoel Stanley         if (s->len != 1) {
17646560cb1SJoel Stanley             qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid recv sequence\n",
17746560cb1SJoel Stanley                           __func__);
17846560cb1SJoel Stanley         }
17946560cb1SJoel Stanley         break;
18046560cb1SJoel Stanley     default:
18146560cb1SJoel Stanley         break;
18246560cb1SJoel Stanley     }
18346560cb1SJoel Stanley 
18446560cb1SJoel Stanley     return 0;
18546560cb1SJoel Stanley }
18646560cb1SJoel Stanley 
18746560cb1SJoel Stanley static const VMStateDescription vmstate_dps310 = {
18846560cb1SJoel Stanley     .name = "DPS310",
18946560cb1SJoel Stanley     .version_id = 0,
19046560cb1SJoel Stanley     .minimum_version_id = 0,
191af10fff2SRichard Henderson     .fields = (const VMStateField[]) {
19246560cb1SJoel Stanley         VMSTATE_UINT8(len, DPS310State),
19346560cb1SJoel Stanley         VMSTATE_UINT8_ARRAY(regs, DPS310State, NUM_REGISTERS),
19446560cb1SJoel Stanley         VMSTATE_UINT8(pointer, DPS310State),
19546560cb1SJoel Stanley         VMSTATE_I2C_SLAVE(i2c, DPS310State),
19646560cb1SJoel Stanley         VMSTATE_END_OF_LIST()
19746560cb1SJoel Stanley     }
19846560cb1SJoel Stanley };
19946560cb1SJoel Stanley 
dps310_class_init(ObjectClass * klass,void * data)20046560cb1SJoel Stanley static void dps310_class_init(ObjectClass *klass, void *data)
20146560cb1SJoel Stanley {
20246560cb1SJoel Stanley     DeviceClass *dc = DEVICE_CLASS(klass);
20346560cb1SJoel Stanley     I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
20446560cb1SJoel Stanley 
20546560cb1SJoel Stanley     k->event = dps310_event;
20646560cb1SJoel Stanley     k->recv = dps310_rx;
20746560cb1SJoel Stanley     k->send = dps310_tx;
208*e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, dps310_reset);
20946560cb1SJoel Stanley     dc->vmsd = &vmstate_dps310;
21046560cb1SJoel Stanley }
21146560cb1SJoel Stanley 
21246560cb1SJoel Stanley static const TypeInfo dps310_info = {
21346560cb1SJoel Stanley     .name          = TYPE_DPS310,
21446560cb1SJoel Stanley     .parent        = TYPE_I2C_SLAVE,
21546560cb1SJoel Stanley     .instance_size = sizeof(DPS310State),
21646560cb1SJoel Stanley     .class_init    = dps310_class_init,
21746560cb1SJoel Stanley };
21846560cb1SJoel Stanley 
dps310_register_types(void)21946560cb1SJoel Stanley static void dps310_register_types(void)
22046560cb1SJoel Stanley {
22146560cb1SJoel Stanley     type_register_static(&dps310_info);
22246560cb1SJoel Stanley }
22346560cb1SJoel Stanley 
22446560cb1SJoel Stanley type_init(dps310_register_types)
225