obiofan.c revision 1.1 1 /* $NetBSD: obiofan.c,v 1.1 2021/09/10 23:32:17 macallan Exp $ */
2 /* Id: ki2c.c,v 1.7 2002/10/05 09:56:05 tsubai Exp */
3
4 /*-
5 * Copyright (c) 2006 Michael Lorenz
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <sys/param.h>
31 #include <sys/device.h>
32 #include <sys/systm.h>
33 #include <sys/mutex.h>
34 #include <sys/callout.h>
35 #include <sys/time.h>
36
37 #include <dev/ofw/openfirm.h>
38 #include <dev/sysmon/sysmonvar.h>
39 #include <machine/autoconf.h>
40 #include <macppc/dev/obiovar.h>
41
42 #include "opt_obiofan.h"
43
44 #ifdef OBIOFAN_DEBUG
45 #define DPRINTF printf
46 #else
47 #define DPRINTF if (0) printf
48 #endif
49
50 struct obiofan_softc {
51 device_t sc_dev;
52 struct sysmon_envsys *sc_sme;
53 envsys_data_t sc_sensors[4];
54 callout_t sc_callout;
55 time_t sc_stamp;
56 int sc_node;
57 int sc_reg, sc_shift;
58 int sc_count, sc_rpm;
59 };
60
61 int obiofan_match(device_t, cfdata_t, void *);
62 void obiofan_attach(device_t, device_t, void *);
63 static void obiofan_refresh(struct sysmon_envsys *, envsys_data_t *);
64 static void obiofan_update(void *);
65
66 CFATTACH_DECL_NEW(obiofan, sizeof(struct obiofan_softc), obiofan_match,
67 obiofan_attach, NULL, NULL);
68
69 int
70 obiofan_match(device_t parent, cfdata_t match, void *aux)
71 {
72 struct confargs *ca = aux;
73
74 if (strcmp(ca->ca_name, "fans") == 0)
75 return 1;
76
77 return 0;
78 }
79
80 void
81 obiofan_attach(device_t parent, device_t self, void *aux)
82 {
83 struct obiofan_softc *sc = device_private(self);
84 struct confargs *ca = aux;
85 char descr[32] = "fan";
86 int node = ca->ca_node, tc_node;
87 int regs[8], tc_regs[32];
88
89 printf("\n");
90
91 if (OF_getprop(node, "reg", regs, sizeof(regs)) <= 0)
92 return;
93
94 sc->sc_node = node;
95
96 #ifdef OBIOFAN_DEBUG
97 int i;
98 for (i = 0; i < 7; i += 2)
99 printf("%02x: %08x\n", regs[i], obio_read_4(regs[i]));
100 #endif
101
102 tc_node = OF_parent(node);
103
104 if (OF_getprop(tc_node, "platform-do-getTACHCount", tc_regs, 32) <= 0) {
105 aprint_error("no platform-do-getTACHCount\n");
106 return;
107 }
108
109 /*
110 * XXX this is guesswork based on poking around & observation
111 *
112 * the parameter format seems to be:
113 * reg[0] - node number for the fan, or pointer into OF space
114 * reg[1] - 0x08000000
115 * reg[2] - 0x0000001a - varies with different platform-do-*
116 * reg[3] - register number in obio space
117 * reg[4] - bitmask in the register
118 * reg[5] - unknown
119 * reg[6] - unknown
120 *
121 * for now only get the parameters for the 1st fan since that's all we
122 * have on my 7,3
123 */
124
125 sc->sc_reg = tc_regs[3];
126 sc->sc_shift = ffs(tc_regs[4]) - 1;
127
128 OF_getprop(tc_regs[0], "location", descr, 32);
129 DPRINTF("%s: %02x %d\n", descr, sc->sc_reg, sc->sc_shift);
130
131 sc->sc_stamp = time_second;
132 sc->sc_count = obio_read_4(sc->sc_reg) >> sc->sc_shift;
133 sc->sc_rpm = -1;
134
135 sc->sc_sme = sysmon_envsys_create();
136 sc->sc_sme->sme_name = device_xname(self);
137 sc->sc_sme->sme_cookie = sc;
138 sc->sc_sme->sme_refresh = obiofan_refresh;
139
140 sc->sc_sensors[0].units = ENVSYS_SFANRPM;
141 sc->sc_sensors[0].state = ENVSYS_SINVALID;
142 strcpy(sc->sc_sensors[0].desc, descr);
143 sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensors[0]);
144 sysmon_envsys_register(sc->sc_sme);
145
146 callout_init(&sc->sc_callout, 0);
147 callout_setfunc(&sc->sc_callout, obiofan_update, sc);
148 callout_schedule(&sc->sc_callout, mstohz(5000));
149 }
150
151 static void
152 obiofan_update(void *cookie)
153 {
154 struct obiofan_softc *sc = cookie;
155 time_t now = time_second, diff;
156 int spin, spins;
157 diff = now - sc->sc_stamp;
158 if (diff < 5) return;
159 spin = obio_read_4(sc->sc_reg) >> sc->sc_shift;
160 spins = (spin - sc->sc_count) & 0xffff;
161 sc->sc_rpm = spins * 60 / diff;
162 sc->sc_count = spin;
163 sc->sc_stamp = now;
164 DPRINTF("%s %lld %d\n", __func__, diff, spins);
165 callout_schedule(&sc->sc_callout, mstohz(5000));
166 }
167
168 static void
169 obiofan_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
170 {
171 struct obiofan_softc *sc = sme->sme_cookie;
172 if (sc->sc_rpm >= 0) {
173 edata->state = ENVSYS_SVALID;
174 edata->value_cur = sc->sc_rpm;
175 }
176 }
177