1/*	$OpenBSD: thmc50.c,v 1.5 2022/04/06 18:59:28 naddy Exp $	*/
2
3/*
4 * Copyright (c) 2007 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/* THMC50 registers */
27#define THMC50_TEMP0		0x27
28#define THMC50_TEMP1		0x26
29#define THMC50_TEMP2		0x20
30
31/* Sensors */
32#define THMC_TEMP0		0
33#define THMC_TEMP1		1
34#define THMC_TEMP2		2
35#define THMC_NUM_SENSORS	3
36
37struct thmc_softc {
38	struct device	sc_dev;
39	i2c_tag_t	sc_tag;
40	i2c_addr_t	sc_addr;
41
42	struct ksensor	sc_sensor[THMC_NUM_SENSORS];
43	struct ksensordev sc_sensordev;
44};
45
46int	thmc_match(struct device *, void *, void *);
47void	thmc_attach(struct device *, struct device *, void *);
48void	thmc_refresh(void *);
49
50const struct cfattach thmc_ca = {
51	sizeof(struct thmc_softc), thmc_match, thmc_attach
52};
53
54struct cfdriver thmc_cd = {
55	NULL, "thmc", DV_DULL
56};
57
58int
59thmc_match(struct device *parent, void *match, void *aux)
60{
61	struct i2c_attach_args *ia = aux;
62
63	if (strcmp(ia->ia_name, "thmc50") == 0 ||
64	    strcmp(ia->ia_name, "adm1022") == 0 ||
65	    strcmp(ia->ia_name, "adm1028") == 0)
66		return (1);
67	return (0);
68}
69
70void
71thmc_attach(struct device *parent, struct device *self, void *aux)
72{
73	struct thmc_softc *sc = (struct thmc_softc *)self;
74	struct i2c_attach_args *ia = aux;
75	int numsensors = THMC_NUM_SENSORS;
76	int i;
77
78	sc->sc_tag = ia->ia_tag;
79	sc->sc_addr = ia->ia_addr;
80
81	printf(": %s", ia->ia_name);
82
83	/* Initialize sensor data. */
84	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
85	    sizeof(sc->sc_sensordev.xname));
86
87	sc->sc_sensor[THMC_TEMP0].type = SENSOR_TEMP;
88	strlcpy(sc->sc_sensor[THMC_TEMP0].desc, "Internal",
89	    sizeof(sc->sc_sensor[THMC_TEMP0].desc));
90
91	sc->sc_sensor[THMC_TEMP1].type = SENSOR_TEMP;
92	strlcpy(sc->sc_sensor[THMC_TEMP1].desc, "External",
93	    sizeof(sc->sc_sensor[THMC_TEMP1].desc));
94
95	if (strcmp(ia->ia_name, "adm1022") == 0) {
96		/* Only the adm1022 has a THMC50_TEMP2 sensor */
97		sc->sc_sensor[THMC_TEMP2].type = SENSOR_TEMP;
98		strlcpy(sc->sc_sensor[THMC_TEMP2].desc, "External",
99		    sizeof(sc->sc_sensor[THMC_TEMP2].desc));
100	} else {
101		sc->sc_sensor[THMC_TEMP2].type = -1;
102		numsensors--;
103	}
104
105	if (sensor_task_register(sc, thmc_refresh, 5) == NULL) {
106		printf(", unable to register update task\n");
107		return;
108	}
109
110	for (i = 0; i < numsensors; i++)
111		sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
112	sensordev_install(&sc->sc_sensordev);
113
114	printf("\n");
115}
116
117void
118thmc_refresh(void *arg)
119{
120	struct thmc_softc *sc = arg;
121	u_int8_t cmd;
122	int8_t sdata;
123
124	iic_acquire_bus(sc->sc_tag, 0);
125
126	cmd = THMC50_TEMP0;
127	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
128	    sc->sc_addr, &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0) {
129		sc->sc_sensor[THMC_TEMP0].value = 273150000 + 1000000 * sdata;
130		sc->sc_sensor[THMC_TEMP0].flags &= ~SENSOR_FINVALID;
131	} else
132		sc->sc_sensor[THMC_TEMP0].flags |= SENSOR_FINVALID;
133
134	cmd = THMC50_TEMP1;
135	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
136	    sc->sc_addr, &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0) {
137		sc->sc_sensor[THMC_TEMP1].value = 273150000 + 1000000 * sdata;
138		sc->sc_sensor[THMC_TEMP1].flags &= ~SENSOR_FINVALID;
139	} else
140		sc->sc_sensor[THMC_TEMP1].flags |= SENSOR_FINVALID;
141
142	if (sc->sc_sensor[THMC_TEMP2].type > 0) {
143		cmd = THMC50_TEMP2;
144		if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
145		    sc->sc_addr, &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0) {
146			sc->sc_sensor[THMC_TEMP2].value = 273150000 + 1000000 * sdata;
147			sc->sc_sensor[THMC_TEMP2].flags &= ~SENSOR_FINVALID;
148		} else
149			sc->sc_sensor[THMC_TEMP2].flags |= SENSOR_FINVALID;
150	}
151
152	iic_release_bus(sc->sc_tag, 0);
153}
154