xref: /openbsd-src/sys/dev/onewire/owctr.c (revision 471aeecfc619bc9b69519928152daf993376c2a1)
1*471aeecfSnaddy /*	$OpenBSD: owctr.c,v 1.9 2022/04/06 18:59:29 naddy Exp $	*/
200330949Sderaadt /*
300330949Sderaadt  * Copyright (c) 2010 John L. Scarfone <john@scarfone.net>
400330949Sderaadt  *
500330949Sderaadt  * Permission to use, copy, modify, and distribute this software for any
600330949Sderaadt  * purpose with or without fee is hereby granted, provided that the above
700330949Sderaadt  * copyright notice and this permission notice appear in all copies.
800330949Sderaadt  *
900330949Sderaadt  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1000330949Sderaadt  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1100330949Sderaadt  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1200330949Sderaadt  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1300330949Sderaadt  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1400330949Sderaadt  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1500330949Sderaadt  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1600330949Sderaadt  */
1700330949Sderaadt 
1800330949Sderaadt /*
1900330949Sderaadt  * DS2423 1-Wire 4kbit SRAM with Counter family type device driver.
2000330949Sderaadt  * Provides 4096 bits of SRAM and four 32-bit, read-only counters.
2100330949Sderaadt  * This driver provides access to the two externally triggered
2200330949Sderaadt  * counters.
2300330949Sderaadt  */
2400330949Sderaadt 
2500330949Sderaadt #include <sys/param.h>
2600330949Sderaadt #include <sys/systm.h>
2700330949Sderaadt #include <sys/device.h>
28ca4f184dSderaadt #include <sys/malloc.h>
2900330949Sderaadt #include <sys/rwlock.h>
3000330949Sderaadt #include <sys/sensors.h>
3100330949Sderaadt 
3200330949Sderaadt #include <dev/onewire/onewiredevs.h>
3300330949Sderaadt #include <dev/onewire/onewirereg.h>
3400330949Sderaadt #include <dev/onewire/onewirevar.h>
3500330949Sderaadt 
3600330949Sderaadt /* Commands */
3700330949Sderaadt #define	DSCTR_CMD_READ_MEMCOUNTER	0xa5
3800330949Sderaadt 
3900330949Sderaadt /* External counter banks */
4000330949Sderaadt #define DS2423_COUNTER_BANK_A		0x1c0
4100330949Sderaadt #define DS2423_COUNTER_BANK_B		0x1e0
4200330949Sderaadt 
43ca4f184dSderaadt /* Buffer offsets */
44ca4f184dSderaadt #define DS2423_COUNTER_BUF_COUNTER	35
45ca4f184dSderaadt #define DS2423_COUNTER_BUF_CRC		43
46ca4f184dSderaadt 
47ca4f184dSderaadt #define DS2423_COUNTER_BUFSZ		45
48ca4f184dSderaadt 
4900330949Sderaadt struct owctr_softc {
5000330949Sderaadt 	struct device		sc_dev;
5100330949Sderaadt 
5200330949Sderaadt 	void *			sc_onewire;
5300330949Sderaadt 	u_int64_t		sc_rom;
5400330949Sderaadt 
5500330949Sderaadt 	struct ksensordev	sc_sensordev;
5600330949Sderaadt 
5700330949Sderaadt 	struct ksensor		sc_counterA;
5800330949Sderaadt 	struct ksensor		sc_counterB;
5900330949Sderaadt 
6000330949Sderaadt 	struct sensor_task	*sc_sensortask;
6100330949Sderaadt 
6200330949Sderaadt 	struct rwlock		sc_lock;
6300330949Sderaadt };
6400330949Sderaadt 
6500330949Sderaadt int	owctr_match(struct device *, void *, void *);
6600330949Sderaadt void	owctr_attach(struct device *, struct device *, void *);
6700330949Sderaadt int	owctr_detach(struct device *, int);
6800330949Sderaadt int	owctr_activate(struct device *, int);
6900330949Sderaadt 
7000330949Sderaadt void	owctr_update(void *);
7100330949Sderaadt void	owctr_update_counter(void *, int);
7200330949Sderaadt 
73*471aeecfSnaddy const struct cfattach owctr_ca = {
7400330949Sderaadt 	sizeof(struct owctr_softc),
7500330949Sderaadt 	owctr_match,
7600330949Sderaadt 	owctr_attach,
7700330949Sderaadt 	owctr_detach,
7800330949Sderaadt 	owctr_activate
7900330949Sderaadt };
8000330949Sderaadt 
8100330949Sderaadt struct cfdriver owctr_cd = {
8200330949Sderaadt 	NULL, "owctr", DV_DULL
8300330949Sderaadt };
8400330949Sderaadt 
8500330949Sderaadt static const struct onewire_matchfam owctr_fams[] = {
8600330949Sderaadt 	{ ONEWIRE_FAMILY_DS2423 }
8700330949Sderaadt };
8800330949Sderaadt 
8900330949Sderaadt int
owctr_match(struct device * parent,void * match,void * aux)9000330949Sderaadt owctr_match(struct device *parent, void *match, void *aux)
9100330949Sderaadt {
92d78896dbSjasper 	return (onewire_matchbyfam(aux, owctr_fams, nitems(owctr_fams)));
9300330949Sderaadt }
9400330949Sderaadt 
9500330949Sderaadt void
owctr_attach(struct device * parent,struct device * self,void * aux)9600330949Sderaadt owctr_attach(struct device *parent, struct device *self, void *aux)
9700330949Sderaadt {
9800330949Sderaadt 	struct owctr_softc *sc = (struct owctr_softc *)self;
9900330949Sderaadt 	struct onewire_attach_args *oa = aux;
10000330949Sderaadt 
10100330949Sderaadt 	sc->sc_onewire = oa->oa_onewire;
10200330949Sderaadt 	sc->sc_rom = oa->oa_rom;
10300330949Sderaadt 
10400330949Sderaadt 	/* Initialize counter sensors */
10500330949Sderaadt 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
10600330949Sderaadt 		sizeof(sc->sc_sensordev.xname));
10700330949Sderaadt 	sc->sc_counterA.type = SENSOR_INTEGER;
10800330949Sderaadt 	snprintf(sc->sc_counterA.desc, sizeof(sc->sc_counterA.desc),
10900330949Sderaadt 		"Counter A sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom));
11000330949Sderaadt 	sensor_attach(&sc->sc_sensordev, &sc->sc_counterA);
11100330949Sderaadt 	sc->sc_counterB.type = SENSOR_INTEGER;
11200330949Sderaadt 	snprintf(sc->sc_counterB.desc, sizeof(sc->sc_counterB.desc),
11300330949Sderaadt 		"Counter B sn %012llx", ONEWIRE_ROM_SN(oa->oa_rom));
11400330949Sderaadt 	sensor_attach(&sc->sc_sensordev, &sc->sc_counterB);
11500330949Sderaadt 
11600330949Sderaadt 	sc->sc_sensortask = sensor_task_register(sc, owctr_update, 10);
11700330949Sderaadt 	if (sc->sc_sensortask == NULL) {
11800330949Sderaadt 		printf(": unable to register update task\n");
11900330949Sderaadt 		return;
12000330949Sderaadt 	}
12100330949Sderaadt 
12200330949Sderaadt 	sensordev_install(&sc->sc_sensordev);
12300330949Sderaadt 
12400330949Sderaadt 	rw_init(&sc->sc_lock, sc->sc_dev.dv_xname);
12500330949Sderaadt 	printf("\n");
12600330949Sderaadt }
12700330949Sderaadt 
12800330949Sderaadt int
owctr_detach(struct device * self,int flags)12900330949Sderaadt owctr_detach(struct device *self, int flags)
13000330949Sderaadt {
13100330949Sderaadt 	struct owctr_softc *sc = (struct owctr_softc *)self;
13200330949Sderaadt 
13300330949Sderaadt 	rw_enter_write(&sc->sc_lock);
13400330949Sderaadt 	sensordev_deinstall(&sc->sc_sensordev);
13500330949Sderaadt 	if (sc->sc_sensortask != NULL)
13600330949Sderaadt 		sensor_task_unregister(sc->sc_sensortask);
13700330949Sderaadt 	rw_exit_write(&sc->sc_lock);
13800330949Sderaadt 
13900330949Sderaadt 	return (0);
14000330949Sderaadt }
14100330949Sderaadt 
14200330949Sderaadt int
owctr_activate(struct device * self,int act)14300330949Sderaadt owctr_activate(struct device *self, int act)
14400330949Sderaadt {
14500330949Sderaadt 	return (0);
14600330949Sderaadt }
14700330949Sderaadt 
14800330949Sderaadt void
owctr_update(void * arg)14900330949Sderaadt owctr_update(void *arg)
15000330949Sderaadt {
15100330949Sderaadt 	owctr_update_counter(arg, DS2423_COUNTER_BANK_A);
15200330949Sderaadt 	owctr_update_counter(arg, DS2423_COUNTER_BANK_B);
15300330949Sderaadt }
15400330949Sderaadt 
15500330949Sderaadt void
owctr_update_counter(void * arg,int bank)15600330949Sderaadt owctr_update_counter(void *arg, int bank)
15700330949Sderaadt {
15800330949Sderaadt 	struct owctr_softc *sc = arg;
15900330949Sderaadt 	u_int32_t counter;
16000330949Sderaadt 	u_int16_t crc;
161ca4f184dSderaadt 	u_int8_t *buf;
16200330949Sderaadt 
16300330949Sderaadt 	rw_enter_write(&sc->sc_lock);
16400330949Sderaadt 	onewire_lock(sc->sc_onewire, 0);
16500330949Sderaadt 	if (onewire_reset(sc->sc_onewire) != 0)
16600330949Sderaadt 		goto done;
16700330949Sderaadt 
168ca4f184dSderaadt 	buf = malloc(DS2423_COUNTER_BUFSZ, M_DEVBUF, M_NOWAIT);
169ca4f184dSderaadt 	if (buf == NULL) {
170ca4f184dSderaadt 		printf("%s: malloc() failed\n", sc->sc_dev.dv_xname);
171ca4f184dSderaadt 		goto done;
172ca4f184dSderaadt 	}
173ca4f184dSderaadt 
17400330949Sderaadt 	onewire_matchrom(sc->sc_onewire, sc->sc_rom);
175ca4f184dSderaadt 	buf[0] = DSCTR_CMD_READ_MEMCOUNTER;
176ca4f184dSderaadt 	buf[1] = bank;
177ca4f184dSderaadt 	buf[2] = bank >> 8;
178ca4f184dSderaadt 	onewire_write_byte(sc->sc_onewire, buf[0]);
179ca4f184dSderaadt 	onewire_write_byte(sc->sc_onewire, buf[1]);
180ca4f184dSderaadt 	onewire_write_byte(sc->sc_onewire, buf[2]);
181ca4f184dSderaadt 	onewire_read_block(sc->sc_onewire, &buf[3], DS2423_COUNTER_BUFSZ-3);
182ca4f184dSderaadt 
183ca4f184dSderaadt 	crc = onewire_crc16(buf, DS2423_COUNTER_BUFSZ-2);
184ca4f184dSderaadt 	crc ^= buf[DS2423_COUNTER_BUF_CRC]
185ca4f184dSderaadt 		| (buf[DS2423_COUNTER_BUF_CRC+1] << 8);
186ca4f184dSderaadt 	if ( crc != 0xffff) {
18700330949Sderaadt 		printf("%s: invalid CRC\n", sc->sc_dev.dv_xname);
18800330949Sderaadt 		if (bank == DS2423_COUNTER_BANK_A) {
18900330949Sderaadt 			sc->sc_counterA.value = 0;
19000330949Sderaadt 			sc->sc_counterA.status = SENSOR_S_UNKNOWN;
19100330949Sderaadt 			sc->sc_counterA.flags |= SENSOR_FUNKNOWN;
192ca4f184dSderaadt 		} else {
19300330949Sderaadt 			sc->sc_counterB.value = 0;
19400330949Sderaadt 			sc->sc_counterB.status = SENSOR_S_UNKNOWN;
19500330949Sderaadt 			sc->sc_counterB.flags |= SENSOR_FUNKNOWN;
19600330949Sderaadt 		}
197ca4f184dSderaadt 	} else {
198ca4f184dSderaadt 		counter = buf[DS2423_COUNTER_BUF_COUNTER]
199ca4f184dSderaadt 			| (buf[DS2423_COUNTER_BUF_COUNTER+1] << 8)
200ca4f184dSderaadt 			| (buf[DS2423_COUNTER_BUF_COUNTER+2] << 16)
201ca4f184dSderaadt 			| (buf[DS2423_COUNTER_BUF_COUNTER+3] << 24);
202ca4f184dSderaadt 		if (bank == DS2423_COUNTER_BANK_A) {
20300330949Sderaadt 			sc->sc_counterA.value = counter;
20400330949Sderaadt 			sc->sc_counterA.status = SENSOR_S_UNSPEC;
20500330949Sderaadt 			sc->sc_counterA.flags &= ~SENSOR_FUNKNOWN;
206ca4f184dSderaadt 		} else {
20700330949Sderaadt 			sc->sc_counterB.value = counter;
20800330949Sderaadt 			sc->sc_counterB.status = SENSOR_S_UNSPEC;
20900330949Sderaadt 			sc->sc_counterB.flags &= ~SENSOR_FUNKNOWN;
21000330949Sderaadt 		}
21100330949Sderaadt 	}
212ca4f184dSderaadt 
21300330949Sderaadt 	onewire_reset(sc->sc_onewire);
214fae9b34cSderaadt 	free(buf, M_DEVBUF, DS2423_COUNTER_BUFSZ);
21500330949Sderaadt 
21600330949Sderaadt done:
21700330949Sderaadt 	onewire_unlock(sc->sc_onewire);
21800330949Sderaadt 	rw_exit_write(&sc->sc_lock);
21900330949Sderaadt }
220