From: "Cédric Le Goater" <clg@redhat.com>
To: qemu-arm@nongnu.org, qemu-devel@nongnu.org
Cc: "Emmanuel Blot" <emmanuel.blot@free.fr>,
"Cédric Le Goater" <clg@redhat.com>
Subject: [PULL 31/40] hw/sensor: tmp105: add TMP75, TMP175 and LM75B variants
Date: Sun, 6 Sep 2026 19:10:12 +0200 [thread overview]
Message-ID: <20260906171021.26568-32-clg@redhat.com> (raw)
In-Reply-To: <20260906171021.26568-1-clg@redhat.com>
From: Emmanuel Blot <emmanuel.blot@free.fr>
The TI TMP75/TMP175 and the NXP LM75B share the TMP105 register map and
control semantics, differing only in a few details. Model them as
variants of the TMP105, parameterised by a small per-type class
descriptor covering the fault-queue depths, the writable config bits,
the converter resolution, the set-point masks and the TMP75's
alert-clear on thermostat-mode change.
The variant is class data, not migrated state, so the wire format is
unchanged and all variants share the existing vmstate.
While here, align the shared shutdown handling with the hardware:
entering shutdown now clears the ALERT/OS output in interrupt mode,
correcting the base TMP105 as well.
Signed-off-by: Emmanuel Blot <emmanuel.blot@free.fr>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Link: https://lore.kernel.org/qemu-devel/20260731-sanmiguel-bmc-locator-v2-7-1266926ba769@free.fr
Signed-off-by: Cédric Le Goater <clg@redhat.com>
---
include/hw/sensor/tmp105.h | 6 +-
hw/sensor/tmp105.c | 172 ++++++++++++++++++++++++++++++-------
2 files changed, 146 insertions(+), 32 deletions(-)
diff --git a/include/hw/sensor/tmp105.h b/include/hw/sensor/tmp105.h
index daece592e9bc..0698aeead78c 100644
--- a/include/hw/sensor/tmp105.h
+++ b/include/hw/sensor/tmp105.h
@@ -1,5 +1,5 @@
/*
- * Texas Instruments TMP105 Temperature Sensor
+ * Texas Instruments TMP105/TMP75/TMP175/LM75B Temperature Sensor
*
* Browse the data sheet:
*
@@ -14,6 +14,10 @@
#ifndef HW_SENSOR_TMP105_H
#define HW_SENSOR_TMP105_H
+/* TMP75, TMP175 and NXP LM75B are register-compatible with TMP105. */
#define TYPE_TMP105 "tmp105"
+#define TYPE_TMP175 "tmp175"
+#define TYPE_TMP75 "tmp75"
+#define TYPE_LM75B "lm75b"
#endif
diff --git a/hw/sensor/tmp105.c b/hw/sensor/tmp105.c
index fefa66171170..ece0650d703f 100644
--- a/hw/sensor/tmp105.c
+++ b/hw/sensor/tmp105.c
@@ -1,5 +1,5 @@
/*
- * Texas Instruments TMP105 temperature sensor.
+ * Texas Instruments TMP105/TMP75/TMP175/LM75B temperature sensor.
*
* Copyright (C) 2008 Nokia Corporation
* Written by Andrzej Zaborowski <andrew@openedhand.com>
@@ -16,6 +16,13 @@
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Limitations:
+ * - The SMBus Alert Response Address protocol and the general-call commands
+ * are not implemented.
+ * - The over-limit comparison uses the full 8.8 fixed-point temperature and a
+ * ">=" boundary for every variant. The LM75B's 9-bit comparison quantisation
+ * and strict-exceed boundary are therefore only approximated.
*/
#include "qemu/osdep.h"
@@ -31,15 +38,8 @@
#include "migration/vmstate.h"
#include "trace.h"
-OBJECT_DECLARE_SIMPLE_TYPE(TMP105State, TMP105)
+OBJECT_DECLARE_TYPE(TMP105State, TMP105Class, TMP105)
-/**
- * TMP105State:
- * @config: Bits 5 and 6 (value 32 and 64) determine the precision of the
- * temperature. See Table 8 in the data sheet.
- *
- * @see_also: http://www.ti.com/lit/gpn/tmp105
- */
struct TMP105State {
/*< private >*/
I2CSlave parent_obj;
@@ -53,7 +53,7 @@ struct TMP105State {
uint8_t config;
int16_t temperature;
int16_t limit[2];
- int faults;
+ uint8_t faults;
uint8_t fault_count;
uint8_t alarm;
/*
@@ -65,6 +65,27 @@ struct TMP105State {
bool detect_falling;
};
+/*
+ * Per-device-model parameters. The TMP105, TMP75, TMP175 and LM75B share the
+ * same register map and control semantics; they differ only in a handful of
+ * details captured here.
+ *
+ * @faultq: fault-queue length table selected by Config bits
+ * @config_wmask: writable Config bits. The LM75B has no resolution (R1:R0) or
+ * one-shot (OS) bits.
+ * @fixed_res: converter resolution field pinned by the device, or -1 when it is
+ * software-selectable.
+ * @limit_lsb_mask: low-byte mask applied to the T_LOW/T_HIGH limit registers.
+ */
+struct TMP105Class {
+ I2CSlaveClass parent_class;
+ const uint8_t *faultq;
+ uint8_t config_wmask;
+ int8_t fixed_res;
+ uint8_t limit_lsb_mask;
+ bool tm_change_clears_alert;
+};
+
FIELD(CONFIG, SHUTDOWN_MODE, 0, 1)
FIELD(CONFIG, THERMOSTAT_MODE, 1, 1)
FIELD(CONFIG, POLARITY, 2, 1)
@@ -152,10 +173,11 @@ static void tmp105_set_temperature(Object *obj, Visitor *v, const char *name,
tmp105_alarm_update(s, false);
}
-static const int tmp105_faultq[4] = { 1, 2, 4, 6 };
-
static void tmp105_read(TMP105State *s)
{
+ const TMP105Class *tc = TMP105_GET_CLASS(s);
+ int res;
+
s->len = 0;
if (FIELD_EX8(s->config, CONFIG, THERMOSTAT_MODE)) {
@@ -165,9 +187,11 @@ static void tmp105_read(TMP105State *s)
switch (s->pointer & 3) {
case TMP105_REG_TEMPERATURE:
+ res = tc->fixed_res >= 0 ? tc->fixed_res :
+ FIELD_EX8(s->config, CONFIG, CONVERTER_RESOLUTION);
s->buf[s->len++] = (((uint16_t) s->temperature) >> 8);
s->buf[s->len++] = (((uint16_t) s->temperature) >> 0) &
- (0xf0 << (FIELD_EX8(~s->config, CONFIG, CONVERTER_RESOLUTION)));
+ (0xf0 << (3 - res));
break;
case TMP105_REG_CONFIG:
@@ -190,6 +214,10 @@ static void tmp105_read(TMP105State *s)
static void tmp105_write(TMP105State *s)
{
+ const TMP105Class *tc = TMP105_GET_CLASS(s);
+ uint8_t config, one_shot;
+ bool waking;
+
trace_tmp105_write(s->parent_obj.address, s->pointer);
switch (s->pointer & 3) {
@@ -197,14 +225,27 @@ static void tmp105_write(TMP105State *s)
break;
case TMP105_REG_CONFIG:
- if (FIELD_EX8(s->buf[0] & ~s->config, CONFIG, SHUTDOWN_MODE)) {
+ config = s->buf[0] & tc->config_wmask;
+ if (FIELD_EX8(config & ~s->config, CONFIG, SHUTDOWN_MODE)) {
trace_tmp105_write_shutdown(s->parent_obj.address);
+ if (FIELD_EX8(config, CONFIG, THERMOSTAT_MODE)) {
+ s->alarm = 0;
+ }
+ }
+ if (tc->tm_change_clears_alert &&
+ FIELD_EX8(config ^ s->config, CONFIG, THERMOSTAT_MODE)) {
+ s->alarm = 0;
+ s->fault_count = 0;
+ s->detect_falling = false;
}
- s->config = FIELD_DP8(s->buf[0], CONFIG, ONE_SHOT, 0);
- s->faults = tmp105_faultq[FIELD_EX8(s->config, CONFIG, FAULT_QUEUE)];
- if (FIELD_EX8(s->buf[0], CONFIG, ONE_SHOT) &&
- FIELD_EX8(s->config, CONFIG, SHUTDOWN_MODE)) {
+ waking = FIELD_EX8(s->config & ~config, CONFIG, SHUTDOWN_MODE);
+ one_shot = FIELD_EX8(config, CONFIG, ONE_SHOT);
+ s->config = FIELD_DP8(config, CONFIG, ONE_SHOT, 0);
+ s->faults = tc->faultq[FIELD_EX8(s->config, CONFIG, FAULT_QUEUE)];
+ if (one_shot && FIELD_EX8(s->config, CONFIG, SHUTDOWN_MODE)) {
tmp105_alarm_update(s, true);
+ } else if (waking) {
+ tmp105_alarm_update(s, false);
} else {
tmp105_interrupt_update(s);
}
@@ -214,7 +255,8 @@ static void tmp105_write(TMP105State *s)
case TMP105_REG_T_HIGH:
if (s->len >= 3) {
s->limit[s->pointer & 1] = (int16_t)
- ((((uint16_t) s->buf[0]) << 8) | (s->buf[1] & 0xf0));
+ ((((uint16_t) s->buf[0]) << 8) |
+ (s->buf[1] & tc->limit_lsb_mask));
}
tmp105_interrupt_update(s);
break;
@@ -265,8 +307,9 @@ static int tmp105_event(I2CSlave *i2c, enum i2c_event event)
static int tmp105_post_load(void *opaque, int version_id)
{
TMP105State *s = opaque;
+ const TMP105Class *tc = TMP105_GET_CLASS(s);
- s->faults = tmp105_faultq[FIELD_EX8(s->config, CONFIG, FAULT_QUEUE)];
+ s->faults = tc->faultq[FIELD_EX8(s->config, CONFIG, FAULT_QUEUE)];
tmp105_interrupt_update(s);
return 0;
@@ -339,11 +382,12 @@ static const VMStateDescription vmstate_tmp105 = {
static void tmp105_reset_hold(Object *obj, ResetType type)
{
TMP105State *s = TMP105(obj);
+ const TMP105Class *tc = TMP105_GET_CLASS(s);
s->temperature = 0;
s->pointer = 0;
s->config = 0;
- s->faults = tmp105_faultq[FIELD_EX8(s->config, CONFIG, FAULT_QUEUE)];
+ s->faults = tc->faultq[FIELD_EX8(s->config, CONFIG, FAULT_QUEUE)];
s->fault_count = 0;
s->alarm = 0;
s->detect_falling = false;
@@ -371,11 +415,25 @@ static void tmp105_initfn(Object *obj)
"Temperature, in millidegrees Celsius");
}
+/*
+ * Fault-queue length selected by Config F1:F0. Row 0 (1/2/4/6) is used by the
+ * TMP105, TMP175 and LM75B; row 1 (1/2/3/4) by the TMP75.
+ */
+static const uint8_t tmp105_faultq[][4] = {
+ { 1, 2, 4, 6 },
+ { 1, 2, 3, 4 },
+};
+
+/* The F1:F0 field must never index past a fault-queue table row. */
+QEMU_BUILD_BUG_ON((1 << R_CONFIG_FAULT_QUEUE_LENGTH) - 1 >=
+ ARRAY_SIZE(tmp105_faultq[0]));
+
static void tmp105_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
+ TMP105Class *tc = TMP105_CLASS(klass);
dc->realize = tmp105_realize;
k->event = tmp105_event;
@@ -383,19 +441,71 @@ static void tmp105_class_init(ObjectClass *klass, const void *data)
k->send = tmp105_tx;
rc->phases.hold = tmp105_reset_hold;
dc->vmsd = &vmstate_tmp105;
+
+ tc->faultq = tmp105_faultq[0];
+ tc->config_wmask = 0xff;
+ tc->fixed_res = -1;
+ tc->limit_lsb_mask = 0xf0;
+ tc->tm_change_clears_alert = false;
}
-static const TypeInfo tmp105_info = {
- .name = TYPE_TMP105,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(TMP105State),
- .instance_init = tmp105_initfn,
- .class_init = tmp105_class_init,
-};
+static void tmp175_class_init(ObjectClass *klass, const void *data)
+{
+ TMP105Class *tc = TMP105_CLASS(klass);
-static void tmp105_register_types(void)
+ tc->faultq = tmp105_faultq[0];
+ tc->config_wmask = 0xff;
+ tc->fixed_res = -1;
+ tc->limit_lsb_mask = 0xf0;
+ tc->tm_change_clears_alert = false;
+}
+
+static void tmp75_class_init(ObjectClass *klass, const void *data)
{
- type_register_static(&tmp105_info);
+ TMP105Class *tc = TMP105_CLASS(klass);
+
+ tc->faultq = tmp105_faultq[1];
+ tc->config_wmask = 0xff;
+ tc->fixed_res = -1;
+ tc->limit_lsb_mask = 0xf0;
+ tc->tm_change_clears_alert = true;
}
-type_init(tmp105_register_types)
+static void lm75b_class_init(ObjectClass *klass, const void *data)
+{
+ TMP105Class *tc = TMP105_CLASS(klass);
+
+ tc->faultq = tmp105_faultq[0];
+ tc->config_wmask = 0x1f;
+ tc->fixed_res = 2;
+ tc->limit_lsb_mask = 0x80;
+ tc->tm_change_clears_alert = false;
+}
+
+static const TypeInfo tmp105_types[] = {
+ {
+ .name = TYPE_TMP105,
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(TMP105State),
+ .class_size = sizeof(TMP105Class),
+ .instance_init = tmp105_initfn,
+ .class_init = tmp105_class_init,
+ },
+ {
+ .name = TYPE_TMP175,
+ .parent = TYPE_TMP105,
+ .class_init = tmp175_class_init,
+ },
+ {
+ .name = TYPE_TMP75,
+ .parent = TYPE_TMP105,
+ .class_init = tmp75_class_init,
+ },
+ {
+ .name = TYPE_LM75B,
+ .parent = TYPE_TMP105,
+ .class_init = lm75b_class_init,
+ },
+};
+
+DEFINE_TYPES(tmp105_types)
--
2.55.0
next prev parent reply other threads:[~2026-09-06 17:15 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-06 17:09 [PULL 00/40] aspeed queue Cédric Le Goater
2026-09-06 17:09 ` [PULL 01/40] hw/misc/aspeed_scu: Set both AST2600 protection key registers on reset Cédric Le Goater
2026-09-06 17:09 ` [PULL 02/40] hw/i2c/aspeed_i2c: Latch received bytes for SMBus block reads Cédric Le Goater
2026-09-06 17:09 ` [PULL 03/40] hw/usb/hcd-ehci: Check for DMA errors in get_dwords()/put_dwords() Cédric Le Goater
2026-09-06 17:09 ` [PULL 04/40] hw/usb/hcd-ehci: Make get_dwords() return bool Cédric Le Goater
2026-09-06 17:09 ` [PULL 05/40] hw/usb/hcd-ehci: Handle get_dwords() failures in async writeback Cédric Le Goater
2026-09-06 17:09 ` [PULL 06/40] hw/misc/aspeed_scu: Support the second random number generator Cédric Le Goater
2026-09-06 17:09 ` [PULL 07/40] tests/qtest/aspeed-hace-utils: Replace g_printerr() with g_test_skip() Cédric Le Goater
2026-09-06 17:09 ` [PULL 08/40] hw/misc/aspeed_acry: Add ASPEED ACRY model Cédric Le Goater
2026-09-06 17:09 ` [PULL 09/40] hw/arm/aspeed_ast2600: Introduce the ACRY SRAM Cédric Le Goater
2026-09-06 17:09 ` [PULL 10/40] hw/arm/aspeed_ast2600: Wire up the ACRY model Cédric Le Goater
2026-09-06 17:09 ` [PULL 11/40] tests/qtest/aspeed-acry-test: Add RSA ModExp tests Cédric Le Goater
2026-09-06 17:09 ` [PULL 12/40] qapi/crypto: Add ECDSA algorithm and curve id Cédric Le Goater
2026-09-06 17:09 ` [PULL 13/40] crypto/akcipher: Support ECDSA sign/verify with gcrypt Cédric Le Goater
2026-09-06 17:09 ` [PULL 14/40] crypto/akcipher: Support ECDSA sign/verify with nettle Cédric Le Goater
2026-09-06 17:09 ` [PULL 15/40] tests/crypto: Add ECDSA sign/verify tests Cédric Le Goater
2026-09-06 17:09 ` [PULL 16/40] hw/arm/aspeed_ast10x0: Remove obsolete unimplemented SBC mapping Cédric Le Goater
2026-09-06 17:09 ` [PULL 17/40] hw/misc/aspeed_sbc: Increase register space to 0x1000 Cédric Le Goater
2026-09-06 17:09 ` [PULL 18/40] hw/arm/aspeed_ast10x0: Wire SEC SRAM to the SBC model Cédric Le Goater
2026-09-06 17:10 ` [PULL 19/40] hw/misc/aspeed_sbc: Support the ECDSA verify command Cédric Le Goater
2026-09-06 17:10 ` [PULL 20/40] tests/qtest: Add ASPEED SBC ECDSA engine test Cédric Le Goater
2026-09-06 17:10 ` [PULL 21/40] hw/usb/aspeed-udc: Add ASPEED UDC device controller Cédric Le Goater
2026-09-06 17:10 ` [PULL 22/40] hw/usb/aspeed-udc: Add ASPEED UDC gadget USB device Cédric Le Goater
2026-09-06 17:10 ` [PULL 23/40] hw/usb/aspeed-udc: Add programmable endpoint DMA transfers Cédric Le Goater
2026-09-06 17:10 ` [PULL 24/40] hw/arm/aspeed_ast2600: Wire up the UDC Cédric Le Goater
2026-09-06 17:10 ` [PULL 25/40] hw/sensor: tmp105: make device state private to the implementation Cédric Le Goater
2026-09-06 17:10 ` [PULL 26/40] hw/sensor: tmp105: name the parent object field parent_obj Cédric Le Goater
2026-09-06 17:10 ` [PULL 27/40] hw/sensor: tmp105: implement Resettable reset Cédric Le Goater
2026-09-06 17:10 ` [PULL 28/40] hw/sensor: tmp105: enforce the configurable fault queue Cédric Le Goater
2026-09-06 17:10 ` [PULL 29/40] hw/sensor: tmp105: describe the temperature property Cédric Le Goater
2026-09-06 17:10 ` [PULL 30/40] hw/arm: aspeed: guard board-local temperature-sensor aliases Cédric Le Goater
2026-09-06 17:10 ` Cédric Le Goater [this message]
2026-09-06 17:10 ` [PULL 32/40] tests/qtest: tmp105: cover the ALERT fault queue Cédric Le Goater
2026-09-06 17:10 ` [PULL 33/40] tests/qtest: tmp105: cover the TMP75, TMP175 and LM75B variants Cédric Le Goater
2026-09-06 17:10 ` [PULL 34/40] tests/qtest: tmp105: cover one-shot and fault-queue write immunity Cédric Le Goater
2026-09-06 17:10 ` [PULL 35/40] tests/qtest: tmp105: cover shutdown clearing the ALERT across variants Cédric Le Goater
2026-09-06 17:10 ` [PULL 36/40] hw/arm: sanmiguel: add Facebook SanMiguel BMC machine Cédric Le Goater
2026-09-06 17:10 ` [PULL 37/40] hw/arm: sanmiguel: populate EEPROM data Cédric Le Goater
2026-09-06 17:10 ` [PULL 38/40] hw/arm: catalina: use the real TMP75 model Cédric Le Goater
2026-09-06 17:10 ` [PULL 39/40] hw/arm: fuji: use the real TMP75 and LM75B temperature sensors Cédric Le Goater
2026-09-06 17:10 ` [PULL 40/40] tests/functional: aspeed: optionally check the device tree model on boot Cédric Le Goater
2026-09-07 16:35 ` [PULL 00/40] aspeed queue Peter Maydell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260906171021.26568-32-clg@redhat.com \
--to=clg@redhat.com \
--cc=emmanuel.blot@free.fr \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.