10SN/A/*-
2157SN/A * SPDX-License-Identifier: BSD-2-Clause
30SN/A *
40SN/A * Copyright (c) 2010 Andreas Tobler
50SN/A *
60SN/A * Redistribution and use in source and binary forms, with or without
7157SN/A * modification, are permitted provided that the following conditions
80SN/A * are met:
9157SN/A * 1. Redistributions of source code must retain the above copyright
100SN/A *    notice, this list of conditions and the following disclaimer.
110SN/A * 2. Redistributions in binary form must reproduce the above copyright
120SN/A *    notice, this list of conditions and the following disclaimer in the
130SN/A *    documentation and/or other materials provided with the distribution.
140SN/A *
150SN/A * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
160SN/A * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
170SN/A * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
180SN/A * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
190SN/A * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
200SN/A * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21157SN/A * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22157SN/A * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23157SN/A * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
240SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
250SN/A * SUCH DAMAGE.
260SN/A */
270SN/A
280SN/A#include <sys/param.h>
290SN/A#include <sys/bus.h>
300SN/A#include <sys/systm.h>
310SN/A#include <sys/module.h>
320SN/A#include <sys/callout.h>
330SN/A#include <sys/conf.h>
340SN/A#include <sys/cpu.h>
350SN/A#include <sys/ctype.h>
360SN/A#include <sys/kernel.h>
370SN/A#include <sys/reboot.h>
380SN/A#include <sys/rman.h>
390SN/A#include <sys/sysctl.h>
400SN/A#include <sys/limits.h>
410SN/A
420SN/A#include <machine/bus.h>
430SN/A#include <machine/md_var.h>
440SN/A
450SN/A#include <dev/iicbus/iicbus.h>
460SN/A#include <dev/iicbus/iiconf.h>
470SN/A
480SN/A#include <dev/ofw/openfirm.h>
490SN/A#include <dev/ofw/ofw_bus.h>
500SN/A#include <powerpc/powermac/powermac_thermal.h>
510SN/A
520SN/A/* Drivebay sensor: LM75/DS1775. */
530SN/A#define DS1775_TEMP         0x0
540SN/A
550SN/A/* Regular bus attachment functions */
560SN/Astatic int  ds1775_probe(device_t);
57672Savstepanstatic int  ds1775_attach(device_t);
58672Savstepan
59672Savstepanstruct ds1775_softc {
600SN/A	struct pmac_therm	sc_sensor;
610SN/A	device_t		sc_dev;
620SN/A	struct intr_config_hook enum_hook;
630SN/A	uint32_t                sc_addr;
640SN/A};
650SN/A
660SN/A/* Utility functions */
670SN/Astatic int  ds1775_sensor_read(struct ds1775_softc *sc);
680SN/Astatic int  ds1775_sensor_sysctl(SYSCTL_HANDLER_ARGS);
690SN/Astatic void ds1775_start(void *xdev);
700SN/Astatic int  ds1775_read_2(device_t dev, uint32_t addr, uint8_t reg,
710SN/A			  uint16_t *data);
720SN/A
730SN/Astatic device_method_t  ds1775_methods[] = {
740SN/A	/* Device interface */
750SN/A	DEVMETHOD(device_probe,		ds1775_probe),
760SN/A	DEVMETHOD(device_attach,	ds1775_attach),
770SN/A	{ 0, 0 },
780SN/A};
790SN/A
800SN/Astatic driver_t ds1775_driver = {
810SN/A	"ds1775",
820SN/A	ds1775_methods,
830SN/A	sizeof(struct ds1775_softc)
840SN/A};
850SN/A
860SN/ADRIVER_MODULE(ds1775, iicbus, ds1775_driver, 0, 0);
870SN/A
880SN/Astatic int
890SN/Ads1775_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data)
900SN/A{
910SN/A	uint8_t buf[4];
920SN/A	int err, try = 0;
930SN/A
940SN/A	struct iic_msg msg[2] = {
950SN/A	    { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &reg },
960SN/A	    { addr, IIC_M_RD, 2, buf },
970SN/A	};
980SN/A
990SN/A	for (;;)
1000SN/A	{
1010SN/A		err = iicbus_transfer(dev, msg, nitems(msg));
1020SN/A		if (err != 0)
1030SN/A			goto retry;
1040SN/A
1050SN/A		*data = *((uint16_t*)buf);
1060SN/A		return (0);
1070SN/A	retry:
1080SN/A		if (++try > 5) {
1090SN/A			device_printf(dev, "iicbus read failed\n");
1100SN/A			return (-1);
1110SN/A		}
1120SN/A		pause("ds1775_read_2", hz);
1130SN/A	}
1140SN/A}
1150SN/A
1160SN/Astatic int
1170SN/Ads1775_probe(device_t dev)
1180SN/A{
1190SN/A	const char  *name, *compatible;
1200SN/A	struct ds1775_softc *sc;
1210SN/A
1220SN/A	name = ofw_bus_get_name(dev);
1230SN/A	compatible = ofw_bus_get_compat(dev);
1240SN/A
1250SN/A	if (!name)
1260SN/A		return (ENXIO);
1270SN/A
1280SN/A	if (strcmp(name, "temp-monitor") != 0 ||
1290SN/A	    (strcmp(compatible, "ds1775") != 0 &&
1300SN/A	     strcmp(compatible, "lm75") != 0))
1310SN/A		return (ENXIO);
1320SN/A
1330SN/A	sc = device_get_softc(dev);
1340SN/A	sc->sc_dev = dev;
1350SN/A	sc->sc_addr = iicbus_get_addr(dev);
1360SN/A
1370SN/A	device_set_desc(dev, "Temp-Monitor DS1775");
1380SN/A
1390SN/A	return (0);
1400SN/A}
1410SN/A
1420SN/Astatic int
1430SN/Ads1775_attach(device_t dev)
1440SN/A{
1450SN/A	struct ds1775_softc *sc;
1460SN/A
1470SN/A	sc = device_get_softc(dev);
1480SN/A
1490SN/A	sc->enum_hook.ich_func = ds1775_start;
1500SN/A	sc->enum_hook.ich_arg = dev;
1510SN/A
1520SN/A	/* We have to wait until interrupts are enabled. I2C read and write
1530SN/A	 * only works if the interrupts are available.
1540SN/A	 * The unin/i2c is controlled by the htpic on unin. But this is not
1550SN/A	 * the master. The openpic on mac-io is controlling the htpic.
1560SN/A	 * This one gets attached after the mac-io probing and then the
1570SN/A	 * interrupts will be available.
1580SN/A	 */
1590SN/A
1600SN/A	if (config_intrhook_establish(&sc->enum_hook) != 0)
1610SN/A		return (ENOMEM);
1620SN/A
1630SN/A	return (0);
1640SN/A}
1650SN/A
1660SN/Astatic void
1670SN/Ads1775_start(void *xdev)
1680SN/A{
1690SN/A	phandle_t child;
1700SN/A	struct ds1775_softc *sc;
1710SN/A	struct sysctl_oid *oid, *sensroot_oid;
1720SN/A	struct sysctl_ctx_list *ctx;
1730SN/A	ssize_t plen;
1740SN/A	int i;
1750SN/A	char sysctl_name[40], sysctl_desc[40];
1760SN/A
1770SN/A	device_t dev = (device_t)xdev;
1780SN/A
1790SN/A	sc = device_get_softc(dev);
1800SN/A
1810SN/A	child = ofw_bus_get_node(dev);
1820SN/A
1830SN/A	ctx = device_get_sysctl_ctx(dev);
1840SN/A	sensroot_oid = SYSCTL_ADD_NODE(ctx,
1850SN/A	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensor",
1860SN/A	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "DS1775 Sensor Information");
1870SN/A
1880SN/A	if (OF_getprop(child, "hwsensor-zone", &sc->sc_sensor.zone,
1890SN/A		       sizeof(int)) < 0)
1900SN/A		sc->sc_sensor.zone = 0;
1910SN/A
1920SN/A	plen = OF_getprop(child, "hwsensor-location", sc->sc_sensor.name,
1930SN/A			  sizeof(sc->sc_sensor.name));
1940SN/A
1950SN/A	if (plen == -1) {
1960SN/A		strcpy(sysctl_name, "sensor");
1970SN/A	} else {
1980SN/A		for (i = 0; i < strlen(sc->sc_sensor.name); i++) {
1990SN/A			sysctl_name[i] = tolower(sc->sc_sensor.name[i]);
2000SN/A			if (isspace(sysctl_name[i]))
2010SN/A				sysctl_name[i] = '_';
2020SN/A		}
2030SN/A		sysctl_name[i] = 0;
2040SN/A	}
2050SN/A
2060SN/A	/* Make up target temperatures. These are low, for the drive bay. */
2070SN/A	if (sc->sc_sensor.zone == 0) {
2080SN/A		sc->sc_sensor.target_temp = 500 + ZERO_C_TO_K;
2090SN/A		sc->sc_sensor.max_temp = 600 + ZERO_C_TO_K;
2100SN/A	}
2110SN/A	else {
2120SN/A		sc->sc_sensor.target_temp = 300 + ZERO_C_TO_K;
2130SN/A		sc->sc_sensor.max_temp = 600 + ZERO_C_TO_K;
2140SN/A	}
2150SN/A
2160SN/A	sc->sc_sensor.read =
2170SN/A	    (int (*)(struct pmac_therm *sc))(ds1775_sensor_read);
2180SN/A	pmac_thermal_sensor_register(&sc->sc_sensor);
2190SN/A
2200SN/A	sprintf(sysctl_desc,"%s %s", sc->sc_sensor.name, "(C)");
2210SN/A	oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(sensroot_oid),
2220SN/A	    OID_AUTO, sysctl_name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
2230SN/A	    "Sensor Information");
2240SN/A	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "temp",
2250SN/A			CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
2260SN/A			0, ds1775_sensor_sysctl, "IK", sysctl_desc);
2270SN/A
2280SN/A	config_intrhook_disestablish(&sc->enum_hook);
2290SN/A}
2300SN/A
2310SN/Astatic int
2320SN/Ads1775_sensor_read(struct ds1775_softc *sc)
2330SN/A{
2340SN/A	uint16_t buf[2];
2350SN/A	uint16_t read;
2360SN/A	int err;
2370SN/A
2380SN/A	err = ds1775_read_2(sc->sc_dev, sc->sc_addr, DS1775_TEMP, buf);
2390SN/A	if (err < 0)
2400SN/A		return (-1);
2410SN/A
2420SN/A	read = *((int16_t *)buf);
2430SN/A
2440SN/A	/* The default mode of the ADC is 9 bit, the resolution is 0.5 C per
2450SN/A	   bit. The temperature is in tenth kelvin.
2460SN/A	*/
2470SN/A	return (((int16_t)(read) >> 7) * 5 + ZERO_C_TO_K);
2480SN/A}
2490SN/A
2500SN/Astatic int
2510SN/Ads1775_sensor_sysctl(SYSCTL_HANDLER_ARGS)
2520SN/A{
2530SN/A	device_t dev;
2540SN/A	struct ds1775_softc *sc;
2550SN/A	int error;
2560SN/A	int temp;
2570SN/A
2580SN/A	dev = arg1;
2590SN/A	sc = device_get_softc(dev);
2600SN/A
2610SN/A	temp = ds1775_sensor_read(sc);
2620SN/A	if (temp < 0)
2630SN/A		return (EIO);
2640SN/A
2650SN/A	error = sysctl_handle_int(oidp, &temp, 0, req);
2660SN/A
2670SN/A	return (error);
2680SN/A}
2690SN/A