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