]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/jedec_ts/jedec_ts.c
Merge llvm, clang, lld, lldb, compiler-rt and libc++ r307894, and update
[FreeBSD/FreeBSD.git] / sys / dev / jedec_ts / jedec_ts.c
1 /*-
2  * Copyright (c) 2016 Andriy Gapon <avg@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include <sys/param.h>
30 #include <sys/kernel.h>
31 #include <sys/bus.h>
32 #include <sys/endian.h>
33 #include <sys/module.h>
34 #include <sys/rman.h>
35 #include <sys/sysctl.h>
36 #include <sys/systm.h>
37
38 #include <dev/smbus/smbconf.h>
39 #include <dev/smbus/smbus.h>
40
41 #include "smbus_if.h"
42
43
44 /*
45  * SMBus specification defines little-endian byte order,
46  * but it seems that the JEDEC devices expect it to
47  * be big-endian.
48  */
49 static int
50 ts_readw_be(device_t dev, uint8_t reg, uint16_t *val)
51 {
52         device_t bus = device_get_parent(dev);
53         uint8_t addr = smbus_get_addr(dev);
54         int err;
55
56         err = smbus_readw(bus, addr, reg, val);
57         if (err != 0)
58                 return (err);
59         *val = be16toh(*val);
60         return (0);
61 }
62
63 static int
64 ts_temp_sysctl(SYSCTL_HANDLER_ARGS)
65 {
66         device_t dev = arg1;
67         int err;
68         int temp;
69         uint16_t val;
70
71         err = ts_readw_be(dev, 5, &val);
72         if (err != 0)
73                 return (EIO);
74
75         /*
76          * Convert the reading to temperature in 0.0001 Kelvins.
77          * Three most significant bits are flags, the next
78          * most significant bit is a sign bit.
79          * Each step is 0.0625 degrees.
80          */
81         temp = val & 0xfff;
82         if ((val & 0x1000) != 0)
83                 temp = -temp;
84         temp = temp * 625 + 2731500;
85         err = sysctl_handle_int(oidp, &temp, 0, req);
86         return (err);
87 }
88
89 static int
90 ts_probe(device_t dev)
91 {
92         device_set_desc(dev, "DIMM memory sensor");
93         return (BUS_PROBE_DEFAULT);
94 }
95
96 static int
97 ts_attach(device_t dev)
98 {
99         struct sysctl_ctx_list *ctx;
100         struct sysctl_oid_list *tree;
101         int err;
102         uint16_t vendorid;
103         uint16_t devid;
104         uint8_t addr;
105
106         addr = smbus_get_addr(dev);
107         if ((addr & 0xf0) != 0x30) {
108                 /* Up to 8 slave devices starting at 0x30. */
109                 return (ENXIO);
110         }
111
112         err = ts_readw_be(dev, 6, &vendorid);
113         if (err != 0) {
114                 device_printf(dev, "failed to read Manufacturer ID\n");
115                 return (ENXIO);
116         }
117         err = ts_readw_be(dev, 7, &devid);
118         if (err != 0) {
119                 device_printf(dev, "failed to read Device ID\n");
120                 return (ENXIO);
121         }
122         if ((devid & 0xff00) == 0x2200) {
123                 /*
124                  * Defined by JEDEC Standard No. 21-C, Release 26,
125                  * Page 4.1.6 – 24
126                  */
127         } else if (vendorid == 0x104a) {
128                 /*
129                  * STMicroelectronics datasheets say that
130                  * device ID and revision can vary.
131                  * E.g. STT424E02, Doc ID 13448 Rev 8,
132                  * section 4.6, page 26.
133                  */
134         } else if (vendorid == 0xb3 && (devid & 0xff00) == 0x2900) {
135                 /*
136                  * IDT TS3000B3A and TSE2002B3C chips and their variants.
137                  * Revision IDs (the lower byte) can vary.
138                  * http://www.idt.com/sites/default/files/documents/IDT_TSE2002B3C_DST_20100512_120303152056.pdf
139                  * http://www.idt.com/sites/default/files/documents/IDT_TS3000B3A_DST_20101129_120303152013.pdf
140                  */
141         } else {
142                 if (bootverbose) {
143                         device_printf(dev, "Unknown Manufacturer and Device IDs"
144                             ", 0x%x and 0x%x\n", vendorid, devid);
145                 }
146                 return (ENXIO);
147         }
148
149         ctx = device_get_sysctl_ctx(dev);
150         tree = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
151
152         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "temp",
153             CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, 0,
154             ts_temp_sysctl, "IK4", "Current temperature");
155
156         return (0);
157 }
158
159 static int
160 ts_detach(device_t dev)
161 {
162         return (0);
163 }
164
165
166 static device_method_t jedec_ts_methods[] = {
167         /* Methods from the device interface */
168         DEVMETHOD(device_probe,         ts_probe),
169         DEVMETHOD(device_attach,        ts_attach),
170         DEVMETHOD(device_detach,        ts_detach),
171
172         /* Terminate method list */
173         { 0, 0 }
174 };
175
176 static driver_t jedec_ts_driver = {
177         "jedec_ts",
178         jedec_ts_methods,
179         0       /* no softc */
180 };
181
182 static devclass_t jedec_ts_devclass;
183
184 DRIVER_MODULE(jedec_ts, smbus, jedec_ts_driver, jedec_ts_devclass, 0, 0);
185 MODULE_DEPEND(jedec_ts, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
186 MODULE_VERSION(jedec_ts, 1);