xref: /openbsd-src/sys/dev/fdt/mvtemp.c (revision 25c4e8bd056e974b28f4a0ffd39d76c190a56013)
1 /*	$OpenBSD: mvtemp.c,v 1.3 2022/06/28 23:43:12 naddy Exp $	*/
2 /*
3  * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/sensors.h>
22 
23 #include <machine/bus.h>
24 #include <machine/fdt.h>
25 
26 #include <dev/ofw/openfirm.h>
27 #include <dev/ofw/fdt.h>
28 
29 /* Registers */
30 #define TEMP_STAT			0x0000
31 #define TEMP_CTRL0			0x0000
32 #define  TEMP_CTRL0_TSEN_TC_TRIM_MASK	0x7
33 #define  TEMP_CTRL0_TSEN_TC_TRIM_VAL	0x3
34 #define TEMP_CTRL1			0x0004
35 #define  TEMP_CTRL1_TSEN_RESET		(1 << 8)
36 
37 struct mvtemp_softc {
38 	struct device		sc_dev;
39 	bus_space_tag_t		sc_iot;
40 	bus_space_handle_t	sc_stat_ioh;
41 	bus_space_handle_t	sc_ctrl_ioh;
42 
43 	uint32_t		sc_stat_valid;
44 	int32_t			(*sc_calc_temp)(uint32_t);
45 
46 	struct ksensor		sc_sensor;
47 	struct ksensordev	sc_sensordev;
48 };
49 
50 int	mvtemp_match(struct device *, void *, void *);
51 void	mvtemp_attach(struct device *, struct device *, void *);
52 
53 const struct cfattach	mvtemp_ca = {
54 	sizeof (struct mvtemp_softc), mvtemp_match, mvtemp_attach
55 };
56 
57 struct cfdriver mvtemp_cd = {
58 	NULL, "mvtemp", DV_DULL
59 };
60 
61 struct mvtemp_compat {
62 	const char *compat;
63 	uint32_t stat_valid;
64 	void	(*init)(struct mvtemp_softc *);
65 	int32_t	(*calc_temp)(uint32_t);
66 };
67 
68 void	mvtemp_ap806_init(struct mvtemp_softc *);
69 int32_t mvtemp_ap806_calc_temp(uint32_t);
70 void	mvtemp_cp110_init(struct mvtemp_softc *);
71 int32_t mvtemp_cp110_calc_temp(uint32_t);
72 
73 const struct mvtemp_compat mvtemp_compat[] = {
74 	{
75 		"marvell,armada-ap806-thermal", (1 << 16),
76 		mvtemp_ap806_init, mvtemp_ap806_calc_temp,
77 	},
78 	{
79 		"marvell,armada-cp110-thermal", (1 << 10),
80 		mvtemp_cp110_init, mvtemp_cp110_calc_temp,
81 	}
82 };
83 
84 void	mvtemp_refresh_sensors(void *);
85 
86 int
87 mvtemp_match(struct device *parent, void *match, void *aux)
88 {
89 	struct fdt_attach_args *faa = aux;
90 	int i;
91 
92 	for (i = 0; i < nitems(mvtemp_compat); i++) {
93 		if (OF_is_compatible(faa->fa_node, mvtemp_compat[i].compat))
94 			return 1;
95 	}
96 
97 	return 0;
98 }
99 
100 void
101 mvtemp_attach(struct device *parent, struct device *self, void *aux)
102 {
103 	struct mvtemp_softc *sc = (struct mvtemp_softc *)self;
104 	struct fdt_attach_args *faa = aux;
105 	int i;
106 
107 	if (faa->fa_nreg < 2) {
108 		printf(": no registers\n");
109 		return;
110 	}
111 
112 	sc->sc_iot = faa->fa_iot;
113 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
114 	    faa->fa_reg[0].size, 0, &sc->sc_stat_ioh)) {
115 		printf(": can't map registers\n");
116 		return;
117 	}
118 	if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr,
119 	    faa->fa_reg[1].size, 0, &sc->sc_ctrl_ioh)) {
120 		bus_space_unmap(sc->sc_iot, sc->sc_stat_ioh,
121 		    faa->fa_reg[0].size);
122 		printf(": can't map registers\n");
123 		return;
124 	}
125 
126 	printf("\n");
127 
128 	for (i = 0; i < nitems(mvtemp_compat); i++) {
129 		if (OF_is_compatible(faa->fa_node, mvtemp_compat[i].compat)) {
130 			break;
131 		}
132 	}
133 	KASSERT(i < nitems(mvtemp_compat));
134 
135 	mvtemp_compat[i].init(sc);
136 	sc->sc_stat_valid = mvtemp_compat[i].stat_valid;
137 	sc->sc_calc_temp = mvtemp_compat[i].calc_temp;
138 
139 	/* Register sensors. */
140 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
141 	    sizeof(sc->sc_sensordev.xname));
142 	sc->sc_sensor.type = SENSOR_TEMP;
143 	sc->sc_sensor.flags = SENSOR_FINVALID;
144 	sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
145 	sensordev_install(&sc->sc_sensordev);
146 	sensor_task_register(sc, mvtemp_refresh_sensors, 5);
147 }
148 
149 /* AP806 */
150 
151 void
152 mvtemp_ap806_init(struct mvtemp_softc *sc)
153 {
154 }
155 
156 int32_t
157 mvtemp_ap806_calc_temp(uint32_t stat)
158 {
159 	stat = ((stat & 0x3ff) ^ 0x200) - 0x200;
160 	return (stat * 423000) + 150000000 + 273150000;
161 }
162 
163 /* CP110 */
164 
165 void
166 mvtemp_cp110_init(struct mvtemp_softc *sc)
167 {
168 	uint32_t ctrl;
169 
170 	ctrl = bus_space_read_4(sc->sc_iot, sc->sc_ctrl_ioh, TEMP_CTRL1);
171 	ctrl |= TEMP_CTRL1_TSEN_RESET;
172 	bus_space_write_4(sc->sc_iot, sc->sc_ctrl_ioh, TEMP_CTRL1, ctrl);
173 
174 	ctrl = bus_space_read_4(sc->sc_iot, sc->sc_ctrl_ioh, TEMP_CTRL0);
175 	ctrl &= ~TEMP_CTRL0_TSEN_TC_TRIM_MASK;
176 	ctrl |= TEMP_CTRL0_TSEN_TC_TRIM_VAL;
177 	bus_space_write_4(sc->sc_iot, sc->sc_ctrl_ioh, TEMP_CTRL0, ctrl);
178 }
179 
180 int32_t
181 mvtemp_cp110_calc_temp(uint32_t stat)
182 {
183 	return ((stat & 0x3ff) * 476100) - 279100000 + 273150000;
184 }
185 
186 void
187 mvtemp_refresh_sensors(void *arg)
188 {
189 	struct mvtemp_softc *sc = arg;
190 	int32_t stat, temp;
191 
192 	stat = bus_space_read_4(sc->sc_iot, sc->sc_stat_ioh, TEMP_STAT);
193 	temp = sc->sc_calc_temp(stat);
194 	sc->sc_sensor.value = temp;
195 	if ((stat & sc->sc_stat_valid) && temp >= 0)
196 		sc->sc_sensor.flags &= ~SENSOR_FINVALID;
197 	else
198 		sc->sc_sensor.flags |= SENSOR_FINVALID;
199 }
200