1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2025 Oxide Computer Company
14 */
15
16 /*
17 * Minimally emulate a TS5111. We use a basic register template for this. We
18 * allow a minimum number of writable registers, but that doesn't change
19 * behavior for anything. We will ignore any attempts to go to I3C mode or to
20 * change the default read address mode and starting point.
21 */
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <err.h>
26 #include <sys/sysmacros.h>
27 #include <sys/bitext.h>
28
29 #include "i2csimd.h"
30
31 #define TS5111_REGLEN 256
32
33 typedef struct ts5111 {
34 uint8_t ts_data[TS5111_REGLEN];
35 uint8_t ts_curaddr;
36 } ts5111_t;
37
38 /*
39 * Default register values from the spec, ignoring what we're going to set for
40 * the temperature when this is created.
41 */
42 static const uint8_t ts5111_tmpl[TS5111_REGLEN] = {
43 [0x00] = 0x51,
44 [0x01] = 0x11,
45 [0x02] = 0x12,
46 [0x03] = 0x00,
47 [0x04] = 0x01,
48 [0x07] = 0x0e,
49 [0x28] = 0x70,
50 [0x29] = 0x03,
51 [0x32] = 0x50,
52 [0x33] = 0x05
53 };
54
55 /*
56 * While we could emulate and support writes for a subset of the device space
57 * that's writable, we just discard everything other than setting the current
58 * address because we don't need it.
59 */
60 static bool
ts5111_write(void * arg,uint32_t len,const uint8_t * buf)61 ts5111_write(void *arg, uint32_t len, const uint8_t *buf)
62 {
63 ts5111_t *ts = arg;
64
65 if (len > 0) {
66 ts->ts_curaddr = buf[0];
67 }
68
69 return (true);
70 }
71
72 /*
73 * If someone reads past the end of the device, we just wrap to the start.
74 */
75 static bool
ts5111_read(void * arg,uint32_t len,uint8_t * buf)76 ts5111_read(void *arg, uint32_t len, uint8_t *buf)
77 {
78 ts5111_t *ts = arg;
79
80 while (len > 0) {
81 uint16_t rem = sizeof (ts->ts_data) - ts->ts_curaddr + 1;
82 uint16_t toread = MIN(rem, len);
83
84 (void) memcpy(buf, &ts->ts_data[ts->ts_curaddr], toread);
85 buf += toread;
86 len -= toread;
87 ts->ts_curaddr += toread;
88 }
89
90 return (true);
91 }
92
93 static const i2csimd_ops_t ts5111_ops = {
94 .sop_write = ts5111_write,
95 .sop_read = ts5111_read
96 };
97
98 i2csimd_dev_t *
i2csimd_make_ts5111(uint8_t addr,uint16_t temp)99 i2csimd_make_ts5111(uint8_t addr, uint16_t temp)
100 {
101 ts5111_t *ts = calloc(1, sizeof (ts5111_t));
102 if (ts == NULL) {
103 err(EXIT_FAILURE, "failed to allocate a ts5111_t");
104 }
105
106 (void) memcpy(ts->ts_data, ts5111_tmpl, sizeof (ts5111_tmpl));
107 ts->ts_data[0x31] = bitx16(temp, 7, 0);
108 ts->ts_data[0x32] = bitx16(temp, 15, 8);
109
110 i2csimd_dev_t *dev = calloc(1, sizeof (i2csimd_dev_t));
111 if (dev == NULL) {
112 err(EXIT_FAILURE, "failed to allocate i2csimd_dev_t");
113 }
114
115 dev->dev_name = "ts5111";
116 dev->dev_addr = addr;
117 dev->dev_arg = ts;
118 dev->dev_ops = &ts5111_ops;
119
120 return (dev);
121 }
122