xref: /netbsd-src/sys/arch/macppc/dev/psoc.c (revision 8f6fb76507c4e4917cf1aa63b3ca3817038c9543)
1*8f6fb765Smacallan  /* $NetBSD: psoc.c,v 1.8 2021/06/18 23:00:47 macallan Exp $ */
24492437aSmacallan 
34492437aSmacallan /*-
439745b2aSmacallan  * Copyright (c) 2019 Michael Lorenz
54492437aSmacallan  * All rights reserved.
64492437aSmacallan  *
74492437aSmacallan  * Redistribution and use in source and binary forms, with or without
84492437aSmacallan  * modification, are permitted provided that the following conditions
94492437aSmacallan  * are met:
104492437aSmacallan  * 1. Redistributions of source code must retain the above copyright
114492437aSmacallan  *    notice, this list of conditions and the following disclaimer.
124492437aSmacallan  * 2. Redistributions in binary form must reproduce the above copyright
134492437aSmacallan  *    notice, this list of conditions and the following disclaimer in the
144492437aSmacallan  *    documentation and/or other materials provided with the distribution.
154492437aSmacallan  *
164492437aSmacallan  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
174492437aSmacallan  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
184492437aSmacallan  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
194492437aSmacallan  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
204492437aSmacallan  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
214492437aSmacallan  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
224492437aSmacallan  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
234492437aSmacallan  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
244492437aSmacallan  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
254492437aSmacallan  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
264492437aSmacallan  * POSSIBILITY OF SUCH DAMAGE.
274492437aSmacallan  */
284492437aSmacallan 
294492437aSmacallan /*
304492437aSmacallan  * fan controller found in 1GHz TiBook
314492437aSmacallan  *
324492437aSmacallan  * register values from OF:
334492437aSmacallan  * fan1 - 0x20 ( status ), 0x31 ( data )
344492437aSmacallan  * fan2 - 0x26 ( status ), 0x45 ( data )
3557ada224Smacallan  * fan status byte 0:
3657ada224Smacallan  * 0x5* - fan is running, 0x6* - fan stopped
3757ada224Smacallan  * byte 1: unknown, 0x80 seems always set, lower bits seem to fluctuate
3857ada224Smacallan  * byte 2: lower 6 bit seem to indicate speed
3957ada224Smacallan  * fan speed may be lower 6 bit of byte 2 and lower 6 of byte 1
404492437aSmacallan  * temperature sensors start at 6, two bytes each, first appears to be
414492437aSmacallan  * the temperature in degrees Celsius
424492437aSmacallan  */
434492437aSmacallan 
444492437aSmacallan #include <sys/cdefs.h>
45*8f6fb765Smacallan __KERNEL_RCSID(0, "$NetBSD: psoc.c,v 1.8 2021/06/18 23:00:47 macallan Exp $");
464492437aSmacallan 
474492437aSmacallan #include <sys/param.h>
484492437aSmacallan #include <sys/systm.h>
494492437aSmacallan #include <sys/device.h>
504492437aSmacallan #include <sys/conf.h>
514492437aSmacallan #include <sys/bus.h>
524492437aSmacallan #include <sys/time.h>
534492437aSmacallan 
544492437aSmacallan #include <dev/ofw/openfirm.h>
554492437aSmacallan 
564492437aSmacallan #include <dev/i2c/i2cvar.h>
574492437aSmacallan 
584492437aSmacallan #include <dev/sysmon/sysmonvar.h>
594492437aSmacallan 
60be8eeb4cSmacallan #include "opt_psoc.h"
61be8eeb4cSmacallan #ifdef PSOC_DEBUG
62be8eeb4cSmacallan #define DPRINTF printf
63be8eeb4cSmacallan #else
64be8eeb4cSmacallan #define DPRINTF if (0) printf
65be8eeb4cSmacallan #endif
66be8eeb4cSmacallan 
674492437aSmacallan struct psoc_softc {
684492437aSmacallan 	device_t	sc_dev;
694492437aSmacallan 	i2c_tag_t	sc_i2c;
704492437aSmacallan 	i2c_addr_t	sc_addr;
714492437aSmacallan 	int		sc_node;
724492437aSmacallan 
734492437aSmacallan 	struct sysmon_envsys *sc_sme;
744492437aSmacallan 	envsys_data_t	sc_sensors[7];
754492437aSmacallan 	int		sc_nsensors;
764492437aSmacallan 	uint8_t		sc_temp[16];
774492437aSmacallan 	time_t		sc_last;
784492437aSmacallan };
794492437aSmacallan 
804492437aSmacallan static int	psoc_match(device_t, cfdata_t, void *);
814492437aSmacallan static void	psoc_attach(device_t, device_t, void *);
824492437aSmacallan 
834492437aSmacallan static void	psoc_sensors_refresh(struct sysmon_envsys *, envsys_data_t *);
844492437aSmacallan 
8557ada224Smacallan static void	psoc_dump(struct psoc_softc *);
8657ada224Smacallan 
874492437aSmacallan CFATTACH_DECL_NEW(psoc, sizeof(struct psoc_softc),
884492437aSmacallan     psoc_match, psoc_attach, NULL, NULL);
894492437aSmacallan 
904492437aSmacallan static const struct device_compatible_entry compat_data[] = {
9156caee62Sthorpej 	{ .compat = "Psoc" },
92ec189949Sthorpej 	DEVICE_COMPAT_EOL
934492437aSmacallan };
944492437aSmacallan 
954492437aSmacallan static int
psoc_match(device_t parent,cfdata_t match,void * aux)964492437aSmacallan psoc_match(device_t parent, cfdata_t match, void *aux)
974492437aSmacallan {
984492437aSmacallan 	struct i2c_attach_args *ia = aux;
994492437aSmacallan 	int match_result;
1004492437aSmacallan 
1014492437aSmacallan 	if (iic_use_direct_match(ia, match, compat_data, &match_result))
1024492437aSmacallan 		return match_result;
1034492437aSmacallan 
1044492437aSmacallan 	return 0;
1054492437aSmacallan }
1064492437aSmacallan 
1074492437aSmacallan static void
psoc_attach(device_t parent,device_t self,void * aux)1084492437aSmacallan psoc_attach(device_t parent, device_t self, void *aux)
1094492437aSmacallan {
1104492437aSmacallan 	struct psoc_softc *sc = device_private(self);
1114492437aSmacallan 	struct i2c_attach_args *ia = aux;
1124492437aSmacallan 	char path[256];
1134492437aSmacallan 	envsys_data_t *s;
11457ada224Smacallan 	int error, ih, r, i;
1154492437aSmacallan 
1164492437aSmacallan 	sc->sc_dev = self;
1174492437aSmacallan 	sc->sc_i2c = ia->ia_tag;
1184492437aSmacallan 	sc->sc_addr = ia->ia_addr;
1194492437aSmacallan 	sc->sc_node = ia->ia_cookie;
1204492437aSmacallan 	sc->sc_last = 0;
1214492437aSmacallan 
1224492437aSmacallan 	aprint_naive("\n");
1234492437aSmacallan 	aprint_normal(": Psoc fan controller\n");
1244492437aSmacallan 
1254492437aSmacallan 	error = OF_package_to_path(sc->sc_node, path, 256);
1264492437aSmacallan 	path[error] = 0;
127be8eeb4cSmacallan 	DPRINTF("path [%s]\n", path);
1284492437aSmacallan 	ih = OF_open("fan");
1294492437aSmacallan 	OF_call_method_1("fan-init", ih, 0);
130be8eeb4cSmacallan 	DPRINTF("ih %08x\n", ih);
1314492437aSmacallan 
1324492437aSmacallan 	sc->sc_sme = sysmon_envsys_create();
1334492437aSmacallan 	sc->sc_sme->sme_name = device_xname(self);
1344492437aSmacallan 	sc->sc_sme->sme_cookie = sc;
1354492437aSmacallan 	sc->sc_sme->sme_refresh = psoc_sensors_refresh;
1364492437aSmacallan 	sc->sc_nsensors = 0;
1374492437aSmacallan 
13857ada224Smacallan 	psoc_dump(sc);
13957ada224Smacallan 
1404492437aSmacallan 	for (i = 0; i < 4; i++) {
1414492437aSmacallan 		r = i * 2 + 6;
1424492437aSmacallan 		s = &sc->sc_sensors[sc->sc_nsensors];
1434492437aSmacallan 		s->state = ENVSYS_SINVALID;
1444492437aSmacallan 		s->units = ENVSYS_STEMP;
1454492437aSmacallan 		snprintf(s->desc, 16, "temp%d", i);
1464492437aSmacallan 		s->private = r;
1474492437aSmacallan 		sysmon_envsys_sensor_attach(sc->sc_sme, s);
1484492437aSmacallan 		sc->sc_nsensors++;
1494492437aSmacallan 	}
15057ada224Smacallan 
15157ada224Smacallan 	for (r = 0x20; r < 0x2b; r += 0x06) {
1524492437aSmacallan 		s = &sc->sc_sensors[sc->sc_nsensors];
1534492437aSmacallan 		s->state = ENVSYS_SINVALID;
1544492437aSmacallan 		s->units = ENVSYS_SFANRPM;
1554492437aSmacallan 		snprintf(s->desc, 16, "reg %02x", r);
1564492437aSmacallan 		s->private = r;
1574492437aSmacallan 		sysmon_envsys_sensor_attach(sc->sc_sme, s);
1584492437aSmacallan 		sc->sc_nsensors++;
1594492437aSmacallan 	}
16057ada224Smacallan 
1614492437aSmacallan 	sysmon_envsys_register(sc->sc_sme);
1624492437aSmacallan }
1634492437aSmacallan 
1644492437aSmacallan static void
psoc_sensors_refresh(struct sysmon_envsys * sme,envsys_data_t * edata)1654492437aSmacallan psoc_sensors_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
1664492437aSmacallan {
1674492437aSmacallan 	struct psoc_softc *sc = sme->sme_cookie;
1684492437aSmacallan 	uint8_t cmd = 6;
16939745b2aSmacallan 	uint8_t buf[0x28];
17057ada224Smacallan 	int error = 1, data;
1714492437aSmacallan 
1724492437aSmacallan 	if ( edata->private < 0x20) {
1734492437aSmacallan 		cmd = 0;
1744492437aSmacallan 		if ((time_second - sc->sc_last) > 2) {
1754492437aSmacallan 			iic_acquire_bus(sc->sc_i2c, 0);
1764492437aSmacallan 			error = iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP,
1774492437aSmacallan 				    sc->sc_addr, &cmd, 1, sc->sc_temp, 16, 0);
1784492437aSmacallan 			iic_release_bus(sc->sc_i2c, 0);
1794492437aSmacallan 			if (error) return;
1804492437aSmacallan 			sc->sc_last = time_second;
1814492437aSmacallan 		}
1824492437aSmacallan 		error = 0;
1834492437aSmacallan 		if (edata->private > 0) {
1844492437aSmacallan 			data = sc->sc_temp[edata->private];
1854492437aSmacallan 			/* Celsius -> microkelvin */
1864492437aSmacallan 			edata->value_cur = ((int)data * 1000000) + 273150000;
1874492437aSmacallan 		}
18857ada224Smacallan #ifdef PSOC_DEBUG
18957ada224Smacallan 		if (edata->private == 6)
19057ada224Smacallan 			psoc_dump(sc);
19157ada224Smacallan #endif
1924492437aSmacallan 	} else {
19339745b2aSmacallan 		cmd = edata->private;
1944492437aSmacallan 		iic_acquire_bus(sc->sc_i2c, 0);
1954492437aSmacallan 		error = iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP,
19639745b2aSmacallan 			    sc->sc_addr, &cmd, 1, buf, 3, 0);
1974492437aSmacallan 		iic_release_bus(sc->sc_i2c, 0);
1984492437aSmacallan 		if (error) return;
19939745b2aSmacallan 		switch (buf[0] & 0xf0) {
20057ada224Smacallan 			case 0x50:
20139745b2aSmacallan 				data = buf[edata->private - 0x20];
20239745b2aSmacallan 				edata->value_cur = ((buf[2] & 0x3f) << 6) |
20339745b2aSmacallan 						    (buf[1] & 0x3f);
20457ada224Smacallan 				break;
20557ada224Smacallan 			case 0x60:
20657ada224Smacallan 				edata->value_cur = 0;
20757ada224Smacallan 				break;
20857ada224Smacallan 			default:
20939745b2aSmacallan 				error = 0;
2104492437aSmacallan 		}
2114492437aSmacallan 	}
2124492437aSmacallan 	if (error) {
2134492437aSmacallan 		edata->state = ENVSYS_SINVALID;
2144492437aSmacallan 	} else {
2154492437aSmacallan 		edata->state = ENVSYS_SVALID;
2164492437aSmacallan 	}
2174492437aSmacallan }
21857ada224Smacallan 
21957ada224Smacallan static void
psoc_dump(struct psoc_softc * sc)22057ada224Smacallan psoc_dump(struct psoc_softc *sc)
22157ada224Smacallan {
22257ada224Smacallan 	int i, j;
22357ada224Smacallan 	uint8_t data, cmd;
224*8f6fb765Smacallan 
225*8f6fb765Smacallan 	iic_acquire_bus(sc->sc_i2c, 0);
22657ada224Smacallan 	for (i = 0x20; i < 0x5f; i+= 8) {
22757ada224Smacallan 		printf("%02x:", i);
22857ada224Smacallan 		for (j = 0; j < 8; j++) {
22957ada224Smacallan 			cmd = i + j;
23057ada224Smacallan 			data = 0;
23157ada224Smacallan 			iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP,
23257ada224Smacallan 			    sc->sc_addr, &cmd, 1, &data, 1, 0);
23357ada224Smacallan 			printf(" %02x", data);
23457ada224Smacallan 		}
23557ada224Smacallan 		printf("\n");
23657ada224Smacallan 	}
237*8f6fb765Smacallan 	iic_release_bus(sc->sc_i2c, 0);
23857ada224Smacallan }
239