1 /* $OpenBSD: ds1631.c,v 1.13 2022/04/06 18:59:28 naddy Exp $ */
2
3 /*
4 * Copyright (c) 2005 Theo de Raadt
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/device.h>
22 #include <sys/sensors.h>
23
24 #include <dev/i2c/i2cvar.h>
25
26 /* Maxim ds 1631 registers */
27 #define DS1631_START 0x51
28 #define DS1624_START 0xee
29 #define DS1631_TEMP 0xaa
30 #define DS1631_CONTROL 0xac
31 #define DS1631_CONTROL_DONE 0x80
32 #define DS1631_CONTROL_1SHOT 0x01
33
34 /* Sensors */
35 #define MAXDS_TEMP 0
36 #define MAXDS_NUM_SENSORS 1
37
38 struct maxds_softc {
39 struct device sc_dev;
40 i2c_tag_t sc_tag;
41 i2c_addr_t sc_addr;
42
43 struct ksensor sc_sensor[MAXDS_NUM_SENSORS];
44 struct ksensordev sc_sensordev;
45 };
46
47 int maxds_match(struct device *, void *, void *);
48 void maxds_attach(struct device *, struct device *, void *);
49 void maxds_refresh(void *);
50
51 const struct cfattach maxds_ca = {
52 sizeof(struct maxds_softc), maxds_match, maxds_attach
53 };
54
55 struct cfdriver maxds_cd = {
56 NULL, "maxds", DV_DULL
57 };
58
59 int
maxds_match(struct device * parent,void * match,void * aux)60 maxds_match(struct device *parent, void *match, void *aux)
61 {
62 struct i2c_attach_args *ia = aux;
63
64 if (strcmp(ia->ia_name, "ds1631") == 0 ||
65 strcmp(ia->ia_name, "ds1624") == 0 ||
66 strcmp(ia->ia_name, "ds1721") == 0)
67 return (1);
68 return (0);
69 }
70
71 void
maxds_attach(struct device * parent,struct device * self,void * aux)72 maxds_attach(struct device *parent, struct device *self, void *aux)
73 {
74 struct maxds_softc *sc = (struct maxds_softc *)self;
75 struct i2c_attach_args *ia = aux;
76 u_int8_t cmd, data;
77 int i;
78
79 printf(": %s", ia->ia_name);
80
81 sc->sc_tag = ia->ia_tag;
82 sc->sc_addr = ia->ia_addr;
83
84 iic_acquire_bus(sc->sc_tag, 0);
85
86 cmd = DS1631_CONTROL;
87 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
88 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0) {
89 if (data & DS1631_CONTROL_1SHOT) {
90 /*
91 * 1-Shot mode would require us to write every refresh
92 * which is stupid. Put us into continuous mode.
93 */
94 data &= ~DS1631_CONTROL_1SHOT;
95
96 (void) iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
97 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0);
98 //delay(10 * 1000);
99 printf(", continuous");
100 goto dostart;
101 }
102 if (data & DS1631_CONTROL_DONE) {
103 dostart:
104 cmd = DS1631_START;
105 if (strcmp(ia->ia_name, "ds1624") == 0)
106 cmd = DS1624_START;
107 (void) iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
108 sc->sc_addr, &cmd, sizeof cmd, NULL, 0, 0);
109 printf(", starting");
110 }
111 } else {
112 iic_release_bus(sc->sc_tag, 0);
113 printf(", fails to respond\n");
114 return;
115 }
116
117 iic_release_bus(sc->sc_tag, 0);
118
119 /* Initialize sensor data. */
120 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
121 sizeof(sc->sc_sensordev.xname));
122
123 sc->sc_sensor[MAXDS_TEMP].type = SENSOR_TEMP;
124 strlcpy(sc->sc_sensor[MAXDS_TEMP].desc, "Internal",
125 sizeof(sc->sc_sensor[MAXDS_TEMP].desc));
126
127 if (sensor_task_register(sc, maxds_refresh, 5) == NULL) {
128 printf(", unable to register update task\n");
129 return;
130 }
131
132 for (i = 0; i < MAXDS_NUM_SENSORS; i++)
133 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
134 sensordev_install(&sc->sc_sensordev);
135
136 printf("\n");
137 }
138
139 void
maxds_refresh(void * arg)140 maxds_refresh(void *arg)
141 {
142 struct maxds_softc *sc = arg;
143 u_int8_t cmd;
144 u_int16_t data;
145
146 iic_acquire_bus(sc->sc_tag, 0);
147
148 cmd = DS1631_TEMP;
149 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
150 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0) {
151 sc->sc_sensor[MAXDS_TEMP].value = 273150000 +
152 (int)(betoh16(data)) / 8 * 31250;
153 sc->sc_sensor[MAXDS_TEMP].flags &= ~SENSOR_FINVALID;
154 } else
155 sc->sc_sensor[MAXDS_TEMP].flags |= SENSOR_FINVALID;
156
157 iic_release_bus(sc->sc_tag, 0);
158 }
159