xref: /openbsd-src/sys/dev/isa/fins.c (revision d095f71341fedbadd002e8f3b7308751f716f065)
1*d095f713Snaddy /*	$OpenBSD: fins.c,v 1.6 2022/04/08 15:02:28 naddy Exp $	*/
27f3e071bSderaadt 
37f3e071bSderaadt /*
47f3e071bSderaadt  * Copyright (c) 2005, 2006 Mark Kettenis
57f3e071bSderaadt  * Copyright (c) 2007, 2008 Geoff Steckel
67f3e071bSderaadt  *
77f3e071bSderaadt  * Permission to use, copy, modify, and distribute this software for any
87f3e071bSderaadt  * purpose with or without fee is hereby granted, provided that the above
97f3e071bSderaadt  * copyright notice and this permission notice appear in all copies.
107f3e071bSderaadt  *
117f3e071bSderaadt  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
127f3e071bSderaadt  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
137f3e071bSderaadt  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
147f3e071bSderaadt  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
157f3e071bSderaadt  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
167f3e071bSderaadt  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
177f3e071bSderaadt  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
187f3e071bSderaadt  */
197f3e071bSderaadt 
207f3e071bSderaadt #include <sys/param.h>
217f3e071bSderaadt #include <sys/systm.h>
227f3e071bSderaadt #include <sys/device.h>
237f3e071bSderaadt #include <sys/kernel.h>
247f3e071bSderaadt #include <sys/queue.h>
257f3e071bSderaadt #include <sys/sensors.h>
267f3e071bSderaadt #include <machine/bus.h>
277f3e071bSderaadt 
287f3e071bSderaadt #include <dev/isa/isareg.h>
297f3e071bSderaadt #include <dev/isa/isavar.h>
307f3e071bSderaadt 
317f3e071bSderaadt /* Derived from LM78 code.  Only handles chips attached to ISA bus */
327f3e071bSderaadt 
337f3e071bSderaadt /*
347f3e071bSderaadt  * Fintek F71805 registers and constants
357f3e071bSderaadt  * http://www.fintek.com.tw/files/productfiles/F71805F_V025.pdf
367f3e071bSderaadt  * This chip is a multi-io chip with many functions.
377f3e071bSderaadt  * Each function may be relocated in I/O space by the BIOS.
387f3e071bSderaadt  * The base address (2E or 4E) accesses a configuration space which
397f3e071bSderaadt  * has pointers to the individual functions. The config space must be
407f3e071bSderaadt  * unlocked with a cookie and relocked afterwards. The chip ID is stored
417f3e071bSderaadt  * in config space so it is not normally visible.
427f3e071bSderaadt  *
437f3e071bSderaadt  * We assume that the monitor is enabled. We don't try to start or stop it.
447f3e071bSderaadt  * The voltage dividers specified are from reading the chips on one board.
457f3e071bSderaadt  * There is no way to determine what they are in the general case.
467f3e071bSderaadt  * This section of the chip controls the fans. We don't do anything to them.
477f3e071bSderaadt  */
487f3e071bSderaadt 
497f3e071bSderaadt #define FINS_UNLOCK	0x87	/* magic constant - write 2x to select chip */
507f3e071bSderaadt #define FINS_LOCK	0xaa	/* magic constant - write 1x to deselect reg */
517f3e071bSderaadt 
527f3e071bSderaadt /* ISA registers index to an internal register space on chip */
537f3e071bSderaadt #define FINS_ADDR	0x00
547f3e071bSderaadt #define FINS_DATA	0x01
557f3e071bSderaadt 
56794e04e3Sderaadt #define FINS_FUNC_SEL	0x07	/* select which chip function to access */
577f3e071bSderaadt #define FINS_CHIP	0x20	/* chip ID */
58794e04e3Sderaadt #define FINS_MANUF	0x23	/* manufacturer ID */
59794e04e3Sderaadt #define FINS_BASEADDR	0x60	/* I/O base of chip function */
607f3e071bSderaadt 
61794e04e3Sderaadt #define FINS_71806	0x0341	/* same as F71872 */
62794e04e3Sderaadt #define FINS_71805	0x0406
63794e04e3Sderaadt #define FINS_71882	0x0541	/* same as F71883 */
64794e04e3Sderaadt #define FINS_71862	0x0601	/* same as F71863 */
65794e04e3Sderaadt #define FINTEK_ID	0x1934
667f3e071bSderaadt 
67794e04e3Sderaadt #define FINS_FUNC_SENSORS	0x04
68794e04e3Sderaadt #define FINS_FUNC_WATCHDOG	0x07
697f3e071bSderaadt 
70794e04e3Sderaadt /* sensors device registers */
71794e04e3Sderaadt #define FINS_SENS_TMODE(sc)	((sc)->fins_chipid <= FINS_71805 ? 0x01 : 0x6b)
72794e04e3Sderaadt #define FINS_SENS_VDIVS		0x0e
73794e04e3Sderaadt 
74794e04e3Sderaadt /* watchdog device registers (mapped straight to i/o port offsets) */
75794e04e3Sderaadt #define FINS_WDOG_CR0	0x00
76794e04e3Sderaadt #define FINS_WDOG_CR1	0x05
77794e04e3Sderaadt #define FINS_WDOG_TIMER	0x06
78794e04e3Sderaadt 
79794e04e3Sderaadt /* CR0 flags */
80794e04e3Sderaadt #define FINS_WDOG_OUTEN	0x80
81794e04e3Sderaadt 
82794e04e3Sderaadt /* CR1 flags */
83794e04e3Sderaadt #define FINS_WDOG_EN	0x20
84794e04e3Sderaadt #define FINS_WDOG_MINS	0x08
85794e04e3Sderaadt 
86794e04e3Sderaadt #define FINS_MAX_SENSORS 18
877f3e071bSderaadt /*
887f3e071bSderaadt  * Fintek chips typically measure voltages using 8mv steps.
897f3e071bSderaadt  * To measure higher voltages the input is attenuated with (external)
907f3e071bSderaadt  * resistors.  Negative voltages are measured using inverting op amps
917f3e071bSderaadt  * and resistors.  So we have to convert the sensor values back to
927f3e071bSderaadt  * real voltages by applying the appropriate resistor factor.
937f3e071bSderaadt  */
947f3e071bSderaadt #define FRFACT_NONE	8000
957f3e071bSderaadt #define FRFACT(x, y)	(FRFACT_NONE * ((x) + (y)) / (y))
967f3e071bSderaadt #define FNRFACT(x, y)	(-FRFACT_NONE * (x) / (y))
977f3e071bSderaadt 
987f3e071bSderaadt struct fins_softc;
997f3e071bSderaadt 
1007f3e071bSderaadt struct fins_sensor {
1017f3e071bSderaadt 	char *fs_desc;
1027f3e071bSderaadt 	void (*fs_refresh)(struct fins_softc *, int);
103794e04e3Sderaadt 	enum sensor_type fs_type;
104794e04e3Sderaadt 	int fs_aux;
105794e04e3Sderaadt 	u_int8_t fs_reg;
1067f3e071bSderaadt };
1077f3e071bSderaadt 
1087f3e071bSderaadt struct fins_softc {
1097f3e071bSderaadt 	struct device sc_dev;
1107f3e071bSderaadt 
1117f3e071bSderaadt 	struct ksensor fins_ksensors[FINS_MAX_SENSORS];
1127f3e071bSderaadt 	struct ksensordev fins_sensordev;
1137f3e071bSderaadt 	struct sensor_task *fins_sensortask;
114*d095f713Snaddy 	const struct fins_sensor *fins_sensors;
1157f3e071bSderaadt 
116794e04e3Sderaadt 	bus_space_handle_t sc_ioh_sens;
117794e04e3Sderaadt 	bus_space_handle_t sc_ioh_wdog;
1187f3e071bSderaadt 	bus_space_tag_t sc_iot;
119794e04e3Sderaadt 
120794e04e3Sderaadt 	u_int16_t fins_chipid;
121794e04e3Sderaadt 	u_int8_t fins_tempsel;
122794e04e3Sderaadt 	u_int8_t fins_wdog_cr;
1237f3e071bSderaadt };
1247f3e071bSderaadt 
125794e04e3Sderaadt int  fins_match(struct device *, void *, void *);
126794e04e3Sderaadt void fins_attach(struct device *, struct device *, void *);
1273b06f262Smikeb int  fins_activate(struct device *, int);
128794e04e3Sderaadt 
129794e04e3Sderaadt void fins_unlock(bus_space_tag_t, bus_space_handle_t);
130794e04e3Sderaadt void fins_lock(bus_space_tag_t, bus_space_handle_t);
131794e04e3Sderaadt 
132794e04e3Sderaadt u_int8_t fins_read(bus_space_tag_t, bus_space_handle_t, int);
133794e04e3Sderaadt u_int16_t fins_read_2(bus_space_tag_t, bus_space_handle_t, int);
134794e04e3Sderaadt void fins_write(bus_space_tag_t, bus_space_handle_t, int, u_int8_t);
135794e04e3Sderaadt 
136794e04e3Sderaadt static __inline u_int8_t fins_read_sens(struct fins_softc *, int);
137794e04e3Sderaadt static __inline u_int16_t fins_read_sens_2(struct fins_softc *, int);
138794e04e3Sderaadt 
139794e04e3Sderaadt static __inline u_int8_t fins_read_wdog(struct fins_softc *, int);
140794e04e3Sderaadt static __inline void fins_write_wdog(struct fins_softc *, int, u_int8_t);
1417f3e071bSderaadt 
142*d095f713Snaddy void fins_setup_sensors(struct fins_softc *, const struct fins_sensor *);
1437f3e071bSderaadt void fins_refresh(void *);
1447f3e071bSderaadt 
145794e04e3Sderaadt void fins_get_rpm(struct fins_softc *, int);
146794e04e3Sderaadt void fins_get_temp(struct fins_softc *, int);
147794e04e3Sderaadt void fins_get_volt(struct fins_softc *, int);
148794e04e3Sderaadt 
149794e04e3Sderaadt int fins_wdog_cb(void *, int);
1507f3e071bSderaadt 
151471aeecfSnaddy const struct cfattach fins_ca = {
152794e04e3Sderaadt 	sizeof(struct fins_softc),
153794e04e3Sderaadt 	fins_match,
1543b06f262Smikeb 	fins_attach,
1553b06f262Smikeb 	NULL,
1563b06f262Smikeb 	fins_activate
1577f3e071bSderaadt };
1587f3e071bSderaadt 
1597f3e071bSderaadt struct cfdriver fins_cd = {
1607f3e071bSderaadt 	NULL, "fins", DV_DULL
1617f3e071bSderaadt };
1627f3e071bSderaadt 
163*d095f713Snaddy const struct fins_sensor fins_71805_sensors[] = {
164794e04e3Sderaadt 	{ "+3.3V",  fins_get_volt, SENSOR_VOLTS_DC, FRFACT(100, 100),	0x10 },
165794e04e3Sderaadt 	{ "Vtt",    fins_get_volt, SENSOR_VOLTS_DC, FRFACT_NONE,	0x11 },
166794e04e3Sderaadt 	{ "Vram",   fins_get_volt, SENSOR_VOLTS_DC, FRFACT(100, 100),	0x12 },
167794e04e3Sderaadt 	{ "Vchips", fins_get_volt, SENSOR_VOLTS_DC, FRFACT(47, 100),	0x13 },
168794e04e3Sderaadt 	{ "+5V",    fins_get_volt, SENSOR_VOLTS_DC, FRFACT(200, 47),	0x14 },
169794e04e3Sderaadt 	{ "+12V",   fins_get_volt, SENSOR_VOLTS_DC, FRFACT(200, 20),	0x15 },
170794e04e3Sderaadt 	{ "+1.5V",  fins_get_volt, SENSOR_VOLTS_DC, FRFACT_NONE,	0x16 },
171794e04e3Sderaadt 	{ "Vcore",  fins_get_volt, SENSOR_VOLTS_DC, FRFACT_NONE,	0x17 },
172794e04e3Sderaadt 	{ "Vsb",    fins_get_volt, SENSOR_VOLTS_DC, FRFACT(200, 47),	0x18 },
173794e04e3Sderaadt 	{ "Vsbint", fins_get_volt, SENSOR_VOLTS_DC, FRFACT(200, 47),	0x19 },
174794e04e3Sderaadt 	{ "Vbat",   fins_get_volt, SENSOR_VOLTS_DC, FRFACT(200, 47),	0x1a },
1757f3e071bSderaadt 
176794e04e3Sderaadt 	{ NULL, fins_get_temp, SENSOR_TEMP, 0x01, 0x1b },
177794e04e3Sderaadt 	{ NULL, fins_get_temp, SENSOR_TEMP, 0x02, 0x1c },
178794e04e3Sderaadt 	{ NULL, fins_get_temp, SENSOR_TEMP, 0x04, 0x1d },
1797f3e071bSderaadt 
180794e04e3Sderaadt 	{ NULL, fins_get_rpm, SENSOR_FANRPM, 0, 0x20 },
181794e04e3Sderaadt 	{ NULL, fins_get_rpm, SENSOR_FANRPM, 0, 0x22 },
182794e04e3Sderaadt 	{ NULL, fins_get_rpm, SENSOR_FANRPM, 0, 0x24 },
1837f3e071bSderaadt 
1847f3e071bSderaadt 	{ NULL }
1857f3e071bSderaadt };
1867f3e071bSderaadt 
187*d095f713Snaddy const struct fins_sensor fins_71882_sensors[] = {
188794e04e3Sderaadt 	{ "+3.3V",  fins_get_volt, SENSOR_VOLTS_DC, FRFACT(100, 100),	0x20 },
189794e04e3Sderaadt 	{ "Vcore",  fins_get_volt, SENSOR_VOLTS_DC, FRFACT_NONE,	0x21 },
190794e04e3Sderaadt 	{ "Vram",   fins_get_volt, SENSOR_VOLTS_DC, FRFACT(100, 100),	0x22 },
191794e04e3Sderaadt 	{ "Vchips", fins_get_volt, SENSOR_VOLTS_DC, FRFACT(47, 100),	0x23 },
192794e04e3Sderaadt 	{ "+5V",    fins_get_volt, SENSOR_VOLTS_DC, FRFACT(200, 47),	0x24 },
193794e04e3Sderaadt 	{ "+12V",   fins_get_volt, SENSOR_VOLTS_DC, FRFACT(200, 20),	0x25 },
194794e04e3Sderaadt 	{ "+1.5V",  fins_get_volt, SENSOR_VOLTS_DC, FRFACT_NONE,	0x26 },
195794e04e3Sderaadt 	{ "Vsb",    fins_get_volt, SENSOR_VOLTS_DC, FRFACT(100, 100),	0x27 },
196794e04e3Sderaadt 	{ "Vbat",   fins_get_volt, SENSOR_VOLTS_DC, FRFACT(100, 100),	0x28 },
197794e04e3Sderaadt 
198794e04e3Sderaadt 	{ NULL, fins_get_temp, SENSOR_TEMP, 0x02, 0x72 },
199794e04e3Sderaadt 	{ NULL, fins_get_temp, SENSOR_TEMP, 0x04, 0x74 },
200794e04e3Sderaadt 	{ NULL, fins_get_temp, SENSOR_TEMP, 0x08, 0x76 },
201794e04e3Sderaadt 
202794e04e3Sderaadt 	{ NULL, fins_get_rpm, SENSOR_FANRPM, 0, 0xa0 },
203794e04e3Sderaadt 	{ NULL, fins_get_rpm, SENSOR_FANRPM, 0, 0xb0 },
204794e04e3Sderaadt 	{ NULL, fins_get_rpm, SENSOR_FANRPM, 0, 0xc0 },
205794e04e3Sderaadt 	{ NULL, fins_get_rpm, SENSOR_FANRPM, 0, 0xd0 },
206794e04e3Sderaadt 
207794e04e3Sderaadt 	{ NULL }
208794e04e3Sderaadt };
2097f3e071bSderaadt 
2107f3e071bSderaadt int
fins_match(struct device * parent,void * match,void * aux)211794e04e3Sderaadt fins_match(struct device *parent, void *match, void *aux)
2127f3e071bSderaadt {
2137f3e071bSderaadt 	struct isa_attach_args *ia = aux;
214794e04e3Sderaadt 	bus_space_handle_t ioh;
215794e04e3Sderaadt 	bus_space_tag_t iot;
216794e04e3Sderaadt 	int ret = 0;
217794e04e3Sderaadt 	u_int16_t id;
2187f3e071bSderaadt 
2197f3e071bSderaadt 	iot = ia->ia_iot;
220794e04e3Sderaadt 	if (bus_space_map(iot, ia->ipa_io[0].base, 2, 0, &ioh))
2217f3e071bSderaadt 		return (0);
2227f3e071bSderaadt 
2237f3e071bSderaadt 	/* Fintek uses magic cookie locks to distinguish their chips */
224794e04e3Sderaadt 	fins_unlock(iot, ioh);
2257f3e071bSderaadt 
226794e04e3Sderaadt 	fins_write(iot, ioh, FINS_FUNC_SEL, 0);	/* IDs appear only in space 0 */
227794e04e3Sderaadt 	if (fins_read_2(iot, ioh, FINS_MANUF) != FINTEK_ID)
228794e04e3Sderaadt 		goto match_done;
229794e04e3Sderaadt 	id = fins_read_2(iot, ioh, FINS_CHIP);
230794e04e3Sderaadt 	switch(id) {
231794e04e3Sderaadt 	case FINS_71882:
232794e04e3Sderaadt 	case FINS_71862:
233794e04e3Sderaadt 		ia->ipa_nio = 3;
234794e04e3Sderaadt 		fins_write(iot, ioh, FINS_FUNC_SEL, FINS_FUNC_WATCHDOG);
235794e04e3Sderaadt 		ia->ipa_io[2].base = fins_read_2(iot, ioh, FINS_BASEADDR);
236794e04e3Sderaadt 		ia->ipa_io[2].length = 8;
237794e04e3Sderaadt 		fins_write(iot, ioh, FINS_FUNC_SEL, FINS_FUNC_SENSORS);
238794e04e3Sderaadt 		ia->ipa_io[1].base = fins_read_2(iot, ioh, FINS_BASEADDR);
239794e04e3Sderaadt 		ia->ipa_io[1].base += 5;
240794e04e3Sderaadt 		break;
241794e04e3Sderaadt 	case FINS_71806:
242794e04e3Sderaadt 	case FINS_71805:
2437f3e071bSderaadt 		ia->ipa_nio = 2;
244794e04e3Sderaadt 		fins_write(iot, ioh, FINS_FUNC_SEL, FINS_FUNC_SENSORS);
245794e04e3Sderaadt 		ia->ipa_io[1].base = fins_read_2(iot, ioh, FINS_BASEADDR);
246794e04e3Sderaadt 		break;
247794e04e3Sderaadt 	default:
248794e04e3Sderaadt 		goto match_done;
249794e04e3Sderaadt 	}
250794e04e3Sderaadt 	ia->ipa_io[0].length = ia->ipa_io[1].length = 2;
251794e04e3Sderaadt 	ia->ipa_nmem = ia->ipa_nirq = ia->ipa_ndrq = 0;
252794e04e3Sderaadt 	ia->ia_aux = (void *)(u_long)id;
253794e04e3Sderaadt 	ret = 1;
254794e04e3Sderaadt match_done:
255794e04e3Sderaadt 	fins_lock(iot, ioh);
256794e04e3Sderaadt 	return (ret);
2577f3e071bSderaadt }
2587f3e071bSderaadt 
2597f3e071bSderaadt void
fins_attach(struct device * parent,struct device * self,void * aux)260794e04e3Sderaadt fins_attach(struct device *parent, struct device *self, void *aux)
2617f3e071bSderaadt {
262794e04e3Sderaadt 	struct fins_softc *sc = (struct fins_softc *)self;
2637f3e071bSderaadt 	struct isa_attach_args *ia = aux;
2647f3e071bSderaadt 	bus_addr_t iobase;
265794e04e3Sderaadt 	u_int32_t iosize;
266794e04e3Sderaadt 	u_int i;
2677f3e071bSderaadt 
2687f3e071bSderaadt 	sc->sc_iot = ia->ia_iot;
269794e04e3Sderaadt 	sc->fins_chipid = (u_int16_t)(u_long)ia->ia_aux;
2707f3e071bSderaadt 	iobase = ia->ipa_io[1].base;
271794e04e3Sderaadt 	iosize = ia->ipa_io[1].length;
272794e04e3Sderaadt 	if (bus_space_map(sc->sc_iot, iobase, iosize, 0, &sc->sc_ioh_sens)) {
273794e04e3Sderaadt 		printf(": can't map sensor i/o space\n");
2747f3e071bSderaadt 		return;
2757f3e071bSderaadt 	}
276794e04e3Sderaadt 	switch(sc->fins_chipid) {
277794e04e3Sderaadt 	case FINS_71882:
278794e04e3Sderaadt 	case FINS_71862:
279794e04e3Sderaadt 		fins_setup_sensors(sc, fins_71882_sensors);
280794e04e3Sderaadt 		break;
281794e04e3Sderaadt 	case FINS_71806:
282794e04e3Sderaadt 	case FINS_71805:
283794e04e3Sderaadt 		fins_setup_sensors(sc, fins_71805_sensors);
284794e04e3Sderaadt 		break;
285794e04e3Sderaadt 	}
286794e04e3Sderaadt 	sc->fins_sensortask = sensor_task_register(sc, fins_refresh, 5);
287794e04e3Sderaadt 	if (sc->fins_sensortask == NULL) {
288794e04e3Sderaadt 		printf(": can't register update task\n");
289794e04e3Sderaadt 		return;
290794e04e3Sderaadt 	}
291794e04e3Sderaadt 	for (i = 0; sc->fins_sensors[i].fs_refresh != NULL; ++i)
292794e04e3Sderaadt 		sensor_attach(&sc->fins_sensordev, &sc->fins_ksensors[i]);
293794e04e3Sderaadt 	sensordev_install(&sc->fins_sensordev);
294794e04e3Sderaadt 
295794e04e3Sderaadt 	if (sc->fins_chipid <= FINS_71805)
296794e04e3Sderaadt 		goto attach_done;
297794e04e3Sderaadt 	iobase = ia->ipa_io[2].base;
298794e04e3Sderaadt 	iosize = ia->ipa_io[2].length;
299794e04e3Sderaadt 	if (bus_space_map(sc->sc_iot, iobase, iosize, 0, &sc->sc_ioh_wdog)) {
300794e04e3Sderaadt 		printf(": can't map watchdog i/o space\n");
301794e04e3Sderaadt 		return;
302794e04e3Sderaadt 	}
303794e04e3Sderaadt 	sc->fins_wdog_cr = fins_read_wdog(sc, FINS_WDOG_CR1);
304794e04e3Sderaadt 	sc->fins_wdog_cr &= ~(FINS_WDOG_MINS | FINS_WDOG_EN);
305794e04e3Sderaadt 	fins_write_wdog(sc, FINS_WDOG_CR1, sc->fins_wdog_cr);
3062bc62decSderaadt 	wdog_register(fins_wdog_cb, sc);
307794e04e3Sderaadt attach_done:
308794e04e3Sderaadt 	printf("\n");
3097f3e071bSderaadt }
3107f3e071bSderaadt 
3113b06f262Smikeb int
fins_activate(struct device * self,int act)3123b06f262Smikeb fins_activate(struct device *self, int act)
3133b06f262Smikeb {
3143b06f262Smikeb 	switch (act) {
3153b06f262Smikeb 	case DVACT_POWERDOWN:
3163b06f262Smikeb 		wdog_shutdown(self);
3173b06f262Smikeb 		break;
3183b06f262Smikeb 	}
3193b06f262Smikeb 
3203b06f262Smikeb 	return (0);
3213b06f262Smikeb }
3223b06f262Smikeb 
3237f3e071bSderaadt u_int8_t
fins_read(bus_space_tag_t iot,bus_space_handle_t ioh,int reg)324794e04e3Sderaadt fins_read(bus_space_tag_t iot, bus_space_handle_t ioh, int reg)
3257f3e071bSderaadt {
326794e04e3Sderaadt 	bus_space_write_1(iot, ioh, FINS_ADDR, reg);
327794e04e3Sderaadt 	return (bus_space_read_1(iot, ioh, FINS_DATA));
328794e04e3Sderaadt }
3297f3e071bSderaadt 
330794e04e3Sderaadt u_int16_t
fins_read_2(bus_space_tag_t iot,bus_space_handle_t ioh,int reg)331794e04e3Sderaadt fins_read_2(bus_space_tag_t iot, bus_space_handle_t ioh, int reg)
332794e04e3Sderaadt {
333794e04e3Sderaadt 	u_int16_t val;
334794e04e3Sderaadt 
335794e04e3Sderaadt 	bus_space_write_1(iot, ioh, FINS_ADDR, reg);
336794e04e3Sderaadt 	val = bus_space_read_1(iot, ioh, FINS_DATA) << 8;
337794e04e3Sderaadt 	bus_space_write_1(iot, ioh, FINS_ADDR, reg + 1);
338794e04e3Sderaadt 	return (val | bus_space_read_1(iot, ioh, FINS_DATA));
3397f3e071bSderaadt }
3407f3e071bSderaadt 
3417f3e071bSderaadt void
fins_write(bus_space_tag_t iot,bus_space_handle_t ioh,int reg,u_int8_t val)342794e04e3Sderaadt fins_write(bus_space_tag_t iot, bus_space_handle_t ioh, int reg, u_int8_t val)
3437f3e071bSderaadt {
344794e04e3Sderaadt 	bus_space_write_1(iot, ioh, FINS_ADDR, reg);
345794e04e3Sderaadt 	bus_space_write_1(iot, ioh, FINS_DATA, val);
346794e04e3Sderaadt }
3477f3e071bSderaadt 
348794e04e3Sderaadt static __inline u_int8_t
fins_read_sens(struct fins_softc * sc,int reg)349794e04e3Sderaadt fins_read_sens(struct fins_softc *sc, int reg)
350794e04e3Sderaadt {
351794e04e3Sderaadt 	return (fins_read(sc->sc_iot, sc->sc_ioh_sens, reg));
352794e04e3Sderaadt }
353794e04e3Sderaadt 
354794e04e3Sderaadt static __inline u_int16_t
fins_read_sens_2(struct fins_softc * sc,int reg)355794e04e3Sderaadt fins_read_sens_2(struct fins_softc *sc, int reg)
356794e04e3Sderaadt {
357794e04e3Sderaadt 	return (fins_read_2(sc->sc_iot, sc->sc_ioh_sens, reg));
358794e04e3Sderaadt }
359794e04e3Sderaadt 
360794e04e3Sderaadt static __inline u_int8_t
fins_read_wdog(struct fins_softc * sc,int reg)361794e04e3Sderaadt fins_read_wdog(struct fins_softc *sc, int reg)
362794e04e3Sderaadt {
363794e04e3Sderaadt 	return (bus_space_read_1(sc->sc_iot, sc->sc_ioh_wdog, reg));
364794e04e3Sderaadt }
365794e04e3Sderaadt 
366794e04e3Sderaadt static __inline void
fins_write_wdog(struct fins_softc * sc,int reg,u_int8_t val)367794e04e3Sderaadt fins_write_wdog(struct fins_softc *sc, int reg, u_int8_t val)
368794e04e3Sderaadt {
369794e04e3Sderaadt 	bus_space_write_1(sc->sc_iot, sc->sc_ioh_wdog, reg, val);
3707f3e071bSderaadt }
3717f3e071bSderaadt 
3727f3e071bSderaadt void
fins_unlock(bus_space_tag_t iot,bus_space_handle_t ioh)373794e04e3Sderaadt fins_unlock(bus_space_tag_t iot, bus_space_handle_t ioh)
3747f3e071bSderaadt {
375794e04e3Sderaadt 	bus_space_write_1(iot, ioh, 0, FINS_UNLOCK);
376794e04e3Sderaadt 	bus_space_write_1(iot, ioh, 0, FINS_UNLOCK);
3777f3e071bSderaadt }
3787f3e071bSderaadt 
379794e04e3Sderaadt void
fins_lock(bus_space_tag_t iot,bus_space_handle_t ioh)380794e04e3Sderaadt fins_lock(bus_space_tag_t iot, bus_space_handle_t ioh)
3817f3e071bSderaadt {
382794e04e3Sderaadt 	bus_space_write_1(iot, ioh, 0, FINS_LOCK);
383794e04e3Sderaadt 	bus_space_unmap(iot, ioh, 2);
3847f3e071bSderaadt }
3857f3e071bSderaadt 
3867f3e071bSderaadt void
fins_setup_sensors(struct fins_softc * sc,const struct fins_sensor * sensors)387*d095f713Snaddy fins_setup_sensors(struct fins_softc *sc, const struct fins_sensor *sensors)
3887f3e071bSderaadt {
3897f3e071bSderaadt 	int i;
3907f3e071bSderaadt 
391794e04e3Sderaadt 	for (i = 0; sensors[i].fs_refresh != NULL; ++i) {
392794e04e3Sderaadt 		sc->fins_ksensors[i].type = sensors[i].fs_type;
393794e04e3Sderaadt 		if (sensors[i].fs_desc != NULL)
394794e04e3Sderaadt 			strlcpy(sc->fins_ksensors[i].desc, sensors[i].fs_desc,
395794e04e3Sderaadt 				sizeof(sc->fins_ksensors[i].desc));
396794e04e3Sderaadt 	}
3977f3e071bSderaadt 	strlcpy(sc->fins_sensordev.xname, sc->sc_dev.dv_xname,
3987f3e071bSderaadt 		sizeof(sc->fins_sensordev.xname));
3997f3e071bSderaadt 	sc->fins_sensors = sensors;
400794e04e3Sderaadt 	sc->fins_tempsel = fins_read_sens(sc, FINS_SENS_TMODE(sc));
4017f3e071bSderaadt }
4027f3e071bSderaadt 
403794e04e3Sderaadt #if 0
404794e04e3Sderaadt void
405794e04e3Sderaadt fins_get_dividers(struct fins_softc *sc)
406794e04e3Sderaadt {
407794e04e3Sderaadt 	int i, p, m;
408794e04e3Sderaadt 	u_int16_t r = fins_read_sens_2(sc, FINS_SENS_VDIVS);
409794e04e3Sderaadt 
410794e04e3Sderaadt 	for (i = 0; i < 6; ++i) {
411794e04e3Sderaadt 		p = (i < 4) ? i : i + 2;
412794e04e3Sderaadt 		m = (r & (0x03 << p)) >> p;
413794e04e3Sderaadt 		if (m == 3)
414794e04e3Sderaadt 			m = 4;
415794e04e3Sderaadt 		fins_71882_sensors[i + 1].fs_aux = FRFACT_NONE << m;
416794e04e3Sderaadt 	}
417794e04e3Sderaadt }
418794e04e3Sderaadt #endif
419794e04e3Sderaadt 
4207f3e071bSderaadt void
fins_refresh(void * arg)4217f3e071bSderaadt fins_refresh(void *arg)
4227f3e071bSderaadt {
4237f3e071bSderaadt 	struct fins_softc *sc = arg;
4247f3e071bSderaadt 	int i;
4257f3e071bSderaadt 
426794e04e3Sderaadt 	for (i = 0; sc->fins_sensors[i].fs_refresh != NULL; ++i)
4277f3e071bSderaadt 		sc->fins_sensors[i].fs_refresh(sc, i);
4287f3e071bSderaadt }
4297f3e071bSderaadt 
4307f3e071bSderaadt void
fins_get_volt(struct fins_softc * sc,int n)431794e04e3Sderaadt fins_get_volt(struct fins_softc *sc, int n)
4327f3e071bSderaadt {
4337f3e071bSderaadt 	struct ksensor *sensor = &sc->fins_ksensors[n];
434*d095f713Snaddy 	const struct fins_sensor *fs = &sc->fins_sensors[n];
4357f3e071bSderaadt 	int data;
4367f3e071bSderaadt 
437794e04e3Sderaadt 	data = fins_read_sens(sc, fs->fs_reg);
4387f3e071bSderaadt 	if (data == 0xff || data == 0) {
4397f3e071bSderaadt 		sensor->flags |= SENSOR_FINVALID;
4407f3e071bSderaadt 		sensor->value = 0;
4417f3e071bSderaadt 	} else {
4427f3e071bSderaadt 		sensor->flags &= ~SENSOR_FINVALID;
443794e04e3Sderaadt 		sensor->value = data * fs->fs_aux;
4447f3e071bSderaadt 	}
4457f3e071bSderaadt }
4467f3e071bSderaadt 
4477f3e071bSderaadt /* The BIOS seems to add a fudge factor to the CPU temp of +5C */
4487f3e071bSderaadt void
fins_get_temp(struct fins_softc * sc,int n)449794e04e3Sderaadt fins_get_temp(struct fins_softc *sc, int n)
4507f3e071bSderaadt {
4517f3e071bSderaadt 	struct ksensor *sensor = &sc->fins_ksensors[n];
452*d095f713Snaddy 	const struct fins_sensor *fs = &sc->fins_sensors[n];
4537f3e071bSderaadt 	u_int data;
4547f3e071bSderaadt 	u_int max;
4557f3e071bSderaadt 
4567f3e071bSderaadt 	/*
4577f3e071bSderaadt 	 * The data sheet says that the range of the temperature
4587f3e071bSderaadt 	 * sensor is between 0 and 127 or 140 degrees C depending on
4597f3e071bSderaadt 	 * what kind of sensor is used.
4607f3e071bSderaadt 	 * A disconnected sensor seems to read over 110 or so.
4617f3e071bSderaadt 	 */
462794e04e3Sderaadt 	data = fins_read_sens(sc, fs->fs_reg);
4637f3e071bSderaadt 	max = (sc->fins_tempsel & fs->fs_aux) ? 111 : 128;
4647f3e071bSderaadt 	if (data == 0 || data >= max) {	/* disconnected? */
4657f3e071bSderaadt 		sensor->flags |= SENSOR_FINVALID;
4667f3e071bSderaadt 		sensor->value = 0;
4677f3e071bSderaadt 	} else {
4687f3e071bSderaadt 		sensor->flags &= ~SENSOR_FINVALID;
4697f3e071bSderaadt 		sensor->value = data * 1000000 + 273150000;
4707f3e071bSderaadt 	}
4717f3e071bSderaadt }
4727f3e071bSderaadt 
4737f3e071bSderaadt /* The chip holds a fudge factor for BJT sensors */
4747f3e071bSderaadt /* this is currently unused but might be reenabled */
475794e04e3Sderaadt #if 0
4767f3e071bSderaadt void
4777f3e071bSderaadt fins_refresh_offset(struct fins_softc *sc, int n)
4787f3e071bSderaadt {
4797f3e071bSderaadt 	struct ksensor *sensor = &sc->fins_ksensors[n];
480*d095f713Snaddy 	const struct fins_sensor *fs = &sc->fins_sensors[n];
4817f3e071bSderaadt 	u_int data;
4827f3e071bSderaadt 
4837f3e071bSderaadt 	sensor->flags &= ~SENSOR_FINVALID;
484794e04e3Sderaadt 	data = fins_read_sens(sc, fs->fs_reg);
4857f3e071bSderaadt 	data |= ~0 * (data & 0x40);	/* sign extend 7-bit value */
4867f3e071bSderaadt 	sensor->value = data * 1000000 + 273150000;
4877f3e071bSderaadt }
488794e04e3Sderaadt #endif
4897f3e071bSderaadt 
4907f3e071bSderaadt /* fan speed appears to be a 12-bit number */
4917f3e071bSderaadt void
fins_get_rpm(struct fins_softc * sc,int n)492794e04e3Sderaadt fins_get_rpm(struct fins_softc *sc, int n)
4937f3e071bSderaadt {
4947f3e071bSderaadt 	struct ksensor *sensor = &sc->fins_ksensors[n];
495*d095f713Snaddy 	const struct fins_sensor *fs = &sc->fins_sensors[n];
4967f3e071bSderaadt 	int data;
4977f3e071bSderaadt 
498794e04e3Sderaadt 	data = fins_read_sens_2(sc, fs->fs_reg);
4997f3e071bSderaadt 	if (data >= 0xfff) {
5007f3e071bSderaadt 		sensor->value = 0;
5017f3e071bSderaadt 		sensor->flags |= SENSOR_FINVALID;
5027f3e071bSderaadt 	} else {
5037f3e071bSderaadt 		sensor->value = 1500000 / data;
5047f3e071bSderaadt 		sensor->flags &= ~SENSOR_FINVALID;
5057f3e071bSderaadt 	}
5067f3e071bSderaadt }
507794e04e3Sderaadt 
508794e04e3Sderaadt int
fins_wdog_cb(void * arg,int period)509794e04e3Sderaadt fins_wdog_cb(void *arg, int period)
510794e04e3Sderaadt {
511794e04e3Sderaadt 	struct fins_softc *sc = arg;
512794e04e3Sderaadt 	u_int8_t cr0, cr1, t;
513794e04e3Sderaadt 
514794e04e3Sderaadt 	cr0 = fins_read_wdog(sc, FINS_WDOG_CR0) & ~FINS_WDOG_OUTEN;
515794e04e3Sderaadt 	fins_write_wdog(sc, FINS_WDOG_CR0, cr0);
516794e04e3Sderaadt 
517794e04e3Sderaadt 	cr1 = sc->fins_wdog_cr;
518794e04e3Sderaadt 	if (period > 0xff) {
519794e04e3Sderaadt 		cr1 |= FINS_WDOG_MINS;
520794e04e3Sderaadt 		t = (period + 59) / 60;
521794e04e3Sderaadt 		period = (int)t * 60;
522794e04e3Sderaadt 	} else if (period > 0)
523794e04e3Sderaadt 		t = period;
524794e04e3Sderaadt 	else
525794e04e3Sderaadt 		return (0);
526794e04e3Sderaadt 
527794e04e3Sderaadt 	fins_write_wdog(sc, FINS_WDOG_TIMER, t);
528794e04e3Sderaadt 	fins_write_wdog(sc, FINS_WDOG_CR0, cr0 | FINS_WDOG_OUTEN);
529794e04e3Sderaadt 	fins_write_wdog(sc, FINS_WDOG_CR1, cr1 | FINS_WDOG_EN);
530794e04e3Sderaadt 	return (period);
531794e04e3Sderaadt }
532