xref: /illumos-gate/usr/src/test/i2c-tests/i2csimd/i2csimd_ts511x.c (revision 0cbe48189888d02563dba9c90132ac391ba233b6)
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