The TMP1075 is register-compatible with the xx75 family but widens the
Config register to 16 bits and adds a read-only Device ID register.
Model it as a new variant of the shared TMP105 device: the control bits
keep the legacy layout in the upper byte, the lower byte has no function
of its own but is writable, and single-byte access stays compatible with
the 8-bit parts. The converter is fixed at 12 bits and the fault queue
matches the TMP75.

Signed-off-by: Emmanuel Blot <[email protected]>
---
 hw/sensor/tmp105.c              | 85 ++++++++++++++++++++++++++++++++++++++++-
 include/hw/sensor/tmp105.h      |  2 +
 include/hw/sensor/tmp105_regs.h |  5 +++
 3 files changed, 91 insertions(+), 1 deletion(-)

diff --git a/hw/sensor/tmp105.c b/hw/sensor/tmp105.c
index ece0650d70..c5aa553d9a 100644
--- a/hw/sensor/tmp105.c
+++ b/hw/sensor/tmp105.c
@@ -1,5 +1,5 @@
 /*
- * Texas Instruments TMP105/TMP75/TMP175/LM75B temperature sensor.
+ * Texas Instruments TMP105/TMP75/TMP175/TMP1075/LM75B temperature sensor.
  *
  * Copyright (C) 2008 Nokia Corporation
  * Written by Andrzej Zaborowski <[email protected]>
@@ -51,6 +51,7 @@ struct TMP105State {
 
     uint8_t pointer;
     uint8_t config;
+    uint8_t config_lsb;
     int16_t temperature;
     int16_t limit[2];
     uint8_t faults;
@@ -76,6 +77,12 @@ struct TMP105State {
  * @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.
+ * @config16: the Config register is 16 bits wide over I2C. Its control bits
+ * occupy the upper byte (mirroring the 8-bit layout); the lower byte has no
+ * function of its own but is writable, and comes up as 0xff. Single-byte
+ * access stays compatible with the 8-bit parts.
+ * @die_id: value of the read-only Device ID register, or 0 when the device has
+ * none.
  */
 struct TMP105Class {
     I2CSlaveClass parent_class;
@@ -84,6 +91,8 @@ struct TMP105Class {
     int8_t fixed_res;
     uint8_t limit_lsb_mask;
     bool tm_change_clears_alert;
+    bool config16;
+    uint16_t die_id;
 };
 
 FIELD(CONFIG, SHUTDOWN_MODE,        0, 1)
@@ -185,6 +194,13 @@ static void tmp105_read(TMP105State *s)
         tmp105_interrupt_update(s);
     }
 
+    if (tc->die_id && (s->pointer & 0x0f) == TMP105_REG_DIE_ID) {
+        s->buf[s->len++] = tc->die_id >> 8;
+        s->buf[s->len++] = tc->die_id & 0xff;
+        trace_tmp105_read(s->parent_obj.address, s->pointer);
+        return;
+    }
+
     switch (s->pointer & 3) {
     case TMP105_REG_TEMPERATURE:
         res = tc->fixed_res >= 0 ? tc->fixed_res :
@@ -196,6 +212,9 @@ static void tmp105_read(TMP105State *s)
 
     case TMP105_REG_CONFIG:
         s->buf[s->len++] = s->config;
+        if (tc->config16) {
+            s->buf[s->len++] = s->config_lsb;
+        }
         break;
 
     case TMP105_REG_T_LOW:
@@ -220,11 +239,29 @@ static void tmp105_write(TMP105State *s)
 
     trace_tmp105_write(s->parent_obj.address, s->pointer);
 
+    if (tc->die_id && (s->pointer & 0x0f) == TMP105_REG_DIE_ID) {
+        return; /* Device ID register is read-only */
+    }
+
     switch (s->pointer & 3) {
     case TMP105_REG_TEMPERATURE:
         break;
 
     case TMP105_REG_CONFIG:
+        /*
+         * The control bits live in the first data byte for every variant (the
+         * upper byte of the TMP1075 16-bit register); a second byte is the low
+         * byte, which drives nothing but keeps what it is given.
+         */
+        if (s->len == 3) {
+            if (tc->config16) {
+                s->config_lsb = s->buf[1];
+            }
+            break;
+        }
+        if (s->len != 2) {
+            break;
+        }
         config = s->buf[0] & tc->config_wmask;
         if (FIELD_EX8(config & ~s->config, CONFIG, SHUTDOWN_MODE)) {
             trace_tmp105_write_shutdown(s->parent_obj.address);
@@ -334,6 +371,13 @@ static bool fault_count_needed(void *opaque)
     return s->fault_count != 0;
 }
 
+static bool config_lsb_needed(void *opaque)
+{
+    TMP105State *s = opaque;
+
+    return TMP105_GET_CLASS(s)->config16 && s->config_lsb != 0xff;
+}
+
 static const VMStateDescription vmstate_tmp105_detect_falling = {
     .name = "TMP105/detect-falling",
     .version_id = 1,
@@ -356,6 +400,17 @@ static const VMStateDescription vmstate_tmp105_fault_count 
= {
     }
 };
 
+static const VMStateDescription vmstate_tmp105_config_lsb = {
+    .name = "TMP105/config-lsb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = config_lsb_needed,
+    .fields = (const VMStateField[]) {
+        VMSTATE_UINT8(config_lsb, TMP105State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_tmp105 = {
     .name = "TMP105",
     .version_id = 0,
@@ -375,6 +430,7 @@ static const VMStateDescription vmstate_tmp105 = {
     .subsections = (const VMStateDescription * const []) {
         &vmstate_tmp105_detect_falling,
         &vmstate_tmp105_fault_count,
+        &vmstate_tmp105_config_lsb,
         NULL
     }
 };
@@ -387,6 +443,7 @@ static void tmp105_reset_hold(Object *obj, ResetType type)
     s->temperature = 0;
     s->pointer = 0;
     s->config = 0;
+    s->config_lsb = tc->config16 ? 0xff : 0;
     s->faults = tc->faultq[FIELD_EX8(s->config, CONFIG, FAULT_QUEUE)];
     s->fault_count = 0;
     s->alarm = 0;
@@ -447,6 +504,8 @@ static void tmp105_class_init(ObjectClass *klass, const 
void *data)
     tc->fixed_res = -1;
     tc->limit_lsb_mask = 0xf0;
     tc->tm_change_clears_alert = false;
+    tc->config16 = false;
+    tc->die_id = 0;
 }
 
 static void tmp175_class_init(ObjectClass *klass, const void *data)
@@ -482,6 +541,25 @@ static void lm75b_class_init(ObjectClass *klass, const 
void *data)
     tc->tm_change_clears_alert = false;
 }
 
+/*
+ * The TMP1075 fixes the converter at 12 bits (its R1:R0 bits select the
+ * conversion rate instead, which this instantaneous model does not track), 
uses
+ * the TMP75 fault-queue mapping, exposes a 16-bit Config register and answers
+ * the Device ID register with 0x7500.
+ */
+static void tmp1075_class_init(ObjectClass *klass, const void *data)
+{
+    TMP105Class *tc = TMP105_CLASS(klass);
+
+    tc->faultq = tmp105_faultq[1];
+    tc->config_wmask = 0xff;
+    tc->fixed_res = 3;
+    tc->limit_lsb_mask = 0xf0;
+    tc->tm_change_clears_alert = true;
+    tc->config16 = true;
+    tc->die_id = TMP1075_DEVICE_ID;
+}
+
 static const TypeInfo tmp105_types[] = {
     {
         .name          = TYPE_TMP105,
@@ -506,6 +584,11 @@ static const TypeInfo tmp105_types[] = {
         .parent        = TYPE_TMP105,
         .class_init    = lm75b_class_init,
     },
+    {
+        .name          = TYPE_TMP1075,
+        .parent        = TYPE_TMP105,
+        .class_init    = tmp1075_class_init,
+    },
 };
 
 DEFINE_TYPES(tmp105_types)
diff --git a/include/hw/sensor/tmp105.h b/include/hw/sensor/tmp105.h
index 0698aeead7..6a30504c7c 100644
--- a/include/hw/sensor/tmp105.h
+++ b/include/hw/sensor/tmp105.h
@@ -19,5 +19,7 @@
 #define TYPE_TMP175 "tmp175"
 #define TYPE_TMP75  "tmp75"
 #define TYPE_LM75B  "lm75b"
+/* TMP1075 adds a 16-bit Config register and a Device ID register. */
+#define TYPE_TMP1075 "tmp1075"
 
 #endif
diff --git a/include/hw/sensor/tmp105_regs.h b/include/hw/sensor/tmp105_regs.h
index ef015ee5cf..ecd0510c2e 100644
--- a/include/hw/sensor/tmp105_regs.h
+++ b/include/hw/sensor/tmp105_regs.h
@@ -21,6 +21,7 @@
  * @TMP105_REG_CONFIG: Configuration register
  * @TMP105_REG_T_LOW: Low temperature register (also known as T_hyst)
  * @TMP105_REG_T_HIGH: High temperature register (also known as T_OS)
+ * @TMP105_REG_DIE_ID: Device ID register (TMP1075 only)
  *
  * The following temperature sensors are
  * compatible with the TMP105 registers:
@@ -46,6 +47,10 @@ typedef enum TMP105Reg {
     TMP105_REG_CONFIG,
     TMP105_REG_T_LOW,
     TMP105_REG_T_HIGH,
+    TMP105_REG_DIE_ID = 0x0f,
 } TMP105Reg;
 
+/* Value returned by the TMP1075 Device ID register. */
+#define TMP1075_DEVICE_ID 0x7500
+
 #endif

-- 
2.53.0-Meta


Reply via email to