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