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