summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2011-05-29 18:35:57 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2011-05-29 18:35:57 +0000
commit95e41991d897ca4ff49ab75bcbf9c81b72c1864f (patch)
tree059a5a044ae0b870bfdd97208a26b7a06d2bda2f /sys/dev
parent1dfa9ab8735324b683e437551bc3829f83c6e8f0 (diff)
downloadFreeBSD-src-95e41991d897ca4ff49ab75bcbf9c81b72c1864f.zip
FreeBSD-src-95e41991d897ca4ff49ab75bcbf9c81b72c1864f.tar.gz
Update the I2C-based temperature/fan drivers to connect to the Powermac
thermal control module. This provides automatic fan management on all G5 PowerMacs and Xserves.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/iicbus/ad7417.c162
-rw-r--r--sys/dev/iicbus/ds1775.c65
-rw-r--r--sys/dev/iicbus/max6690.c50
3 files changed, 186 insertions, 91 deletions
diff --git a/sys/dev/iicbus/ad7417.c b/sys/dev/iicbus/ad7417.c
index aa26d6f..084b9f5 100644
--- a/sys/dev/iicbus/ad7417.c
+++ b/sys/dev/iicbus/ad7417.c
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
+#include <powerpc/powermac/powermac_thermal.h>
#define FCU_ZERO_C_TO_K 2732
@@ -63,8 +64,9 @@ __FBSDID("$FreeBSD$");
uint8_t adc741x_config;
struct ad7417_sensor {
+ struct pmac_therm therm;
+ device_t dev;
int id;
- char location[32];
enum {
ADC7417_TEMP_SENSOR,
ADC7417_ADC_SENSOR
@@ -83,6 +85,9 @@ static int ad7417_read_1(device_t dev, uint32_t addr, uint8_t reg,
uint8_t *data);
static int ad7417_read_2(device_t dev, uint32_t addr, uint8_t reg,
uint16_t *data);
+static int ad7417_diode_read(struct ad7417_sensor *sens);
+static int ad7417_adc_read(struct ad7417_sensor *sens);
+static int ad7417_sensor_read(struct ad7417_sensor *sens);
struct ad7417_softc {
device_t sc_dev;
@@ -243,7 +248,7 @@ ad7417_fill_sensor_prop(device_t dev)
sizeof(location));
while (len < prop_len) {
if (sc->sc_sensors != NULL)
- strcpy(sc->sc_sensors[i].location, location + len);
+ strcpy(sc->sc_sensors[i].therm.name, location + len);
prev_len = strlen(location + len) + 1;
len += prev_len;
i++;
@@ -251,7 +256,7 @@ ad7417_fill_sensor_prop(device_t dev)
if (sc->sc_sensors == NULL)
return (i);
- /* Fill the fan type property. */
+ /* Fill the sensor type property. */
len = 0;
i = 0;
prev_len = 0;
@@ -271,6 +276,36 @@ ad7417_fill_sensor_prop(device_t dev)
for (j = 0; j < i; j++)
sc->sc_sensors[j].id = id[j];
+ /* Fill the sensor zone property. Taken from OF. */
+ prop_len = OF_getprop(child, "hwsensor-zone", id, sizeof(id));
+ for (j = 0; j < i; j++)
+ sc->sc_sensors[j].therm.zone = id[j];
+
+ /* Finish setting up sensor properties */
+ for (j = 0; j < i; j++) {
+ sc->sc_sensors[j].dev = dev;
+
+ /* HACK: Apple wired a random diode to the ADC line */
+ if (strstr(sc->sc_sensors[j].therm.name, "DIODE TEMP")
+ != NULL) {
+ sc->sc_sensors[j].type = ADC7417_TEMP_SENSOR;
+ sc->sc_sensors[j].therm.read =
+ (int (*)(struct pmac_therm *))(ad7417_diode_read);
+ } else {
+ sc->sc_sensors[j].therm.read =
+ (int (*)(struct pmac_therm *))(ad7417_sensor_read);
+ }
+
+ if (sc->sc_sensors[j].type != ADC7417_TEMP_SENSOR)
+ continue;
+
+ /* Make up some ranges */
+ sc->sc_sensors[j].therm.target_temp = 500 + 2732;
+ sc->sc_sensors[j].therm.max_temp = 900 + 2732;
+
+ pmac_thermal_sensor_register(&sc->sc_sensors[j].therm);
+ }
+
return (i);
}
@@ -310,8 +345,9 @@ ad7417_attach(device_t dev)
/* Add sysctls for the sensors. */
for (i = 0; i < sc->sc_nsensors; i++) {
- for (j = 0; j < strlen(sc->sc_sensors[i].location); j++) {
- sysctl_name[j] = tolower(sc->sc_sensors[i].location[j]);
+ for (j = 0; j < strlen(sc->sc_sensors[i].therm.name); j++) {
+ sysctl_name[j] =
+ tolower(sc->sc_sensors[i].therm.name[j]);
if (isspace(sysctl_name[j]))
sysctl_name[j] = '_';
}
@@ -341,7 +377,7 @@ ad7417_attach(device_t dev)
device_printf(dev, "Sensors\n");
for (i = 0; i < sc->sc_nsensors; i++) {
device_printf(dev, "Location: %s ID: %d type: %d\n",
- sc->sc_sensors[i].location,
+ sc->sc_sensors[i].therm.name,
sc->sc_sensors[i].id,
sc->sc_sensors[i].type);
}
@@ -391,44 +427,91 @@ ad7417_get_adc(device_t dev, uint32_t addr, unsigned int *value,
}
static int
-ad7417_sensor_read(device_t dev, struct ad7417_sensor *sens, int *temp)
+ad7417_diode_read(struct ad7417_sensor *sens)
+{
+ static int eeprom_read = 0;
+ static cell_t eeprom[2][40];
+ phandle_t eeprom_node;
+ int rawval, diode_slope, diode_offset;
+ int temp;
+
+ if (!eeprom_read) {
+ eeprom_node = OF_finddevice("/u3/i2c/cpuid@a0");
+ OF_getprop(eeprom_node, "cpuid", eeprom[0], sizeof(eeprom[0]));
+ eeprom_node = OF_finddevice("/u3/i2c/cpuid@a2");
+ OF_getprop(eeprom_node, "cpuid", eeprom[1], sizeof(eeprom[1]));
+ eeprom_read = 1;
+ }
+
+ rawval = ad7417_adc_read(sens);
+ if (strstr(sens->therm.name, "CPU B") != NULL) {
+ diode_slope = eeprom[1][0x11] >> 16;
+ diode_offset = (int16_t)(eeprom[1][0x11] & 0xffff) << 12;
+ } else {
+ diode_slope = eeprom[0][0x11] >> 16;
+ diode_offset = (int16_t)(eeprom[0][0x11] & 0xffff) << 12;
+ }
+
+ temp = (rawval*diode_slope + diode_offset) >> 2;
+ temp = (10*(temp >> 16)) + ((10*(temp & 0xffff)) >> 16);
+
+ return (temp + FCU_ZERO_C_TO_K);
+}
+
+static int
+ad7417_adc_read(struct ad7417_sensor *sens)
+{
+ struct ad7417_softc *sc;
+ uint8_t chan;
+ int temp;
+
+ sc = device_get_softc(sens->dev);
+
+ switch (sens->id) {
+ case 11:
+ case 16:
+ chan = 1;
+ break;
+ case 12:
+ case 17:
+ chan = 2;
+ break;
+ case 13:
+ case 18:
+ chan = 3;
+ break;
+ case 14:
+ case 19:
+ chan = 4;
+ break;
+ default:
+ chan = 1;
+ }
+
+ ad7417_get_adc(sc->sc_dev, sc->sc_addr, &temp, chan);
+
+ return (temp);
+}
+
+
+static int
+ad7417_sensor_read(struct ad7417_sensor *sens)
{
struct ad7417_softc *sc;
+ int temp;
- sc = device_get_softc(dev);
+ sc = device_get_softc(sens->dev);
/* Init the ADC. */
ad7417_init_adc(sc->sc_dev, sc->sc_addr);
if (sens->type == ADC7417_TEMP_SENSOR) {
- ad7417_get_temp(sc->sc_dev, sc->sc_addr, temp);
- *temp += FCU_ZERO_C_TO_K;
+ ad7417_get_temp(sc->sc_dev, sc->sc_addr, &temp);
+ temp += FCU_ZERO_C_TO_K;
} else {
- uint8_t chan;
- switch (sens->id) {
- case 11:
- case 16:
- chan = 1;
- break;
- case 12:
- case 17:
- chan = 2;
- break;
- case 13:
- case 18:
- chan = 3;
- break;
- case 14:
- case 19:
- chan = 4;
- break;
- default:
- chan = 1;
- }
-
- ad7417_get_adc(sc->sc_dev, sc->sc_addr, temp, chan);
+ temp = ad7417_adc_read(sens);
}
- return (0);
+ return (temp);
}
static int
@@ -439,19 +522,16 @@ ad7417_sensor_sysctl(SYSCTL_HANDLER_ARGS)
struct ad7417_sensor *sens;
int value = 0;
int error;
- int temp;
dev = arg1;
sc = device_get_softc(dev);
sens = &sc->sc_sensors[arg2];
- error = ad7417_sensor_read(dev, sens, &value);
- if (error != 0)
- return (error);
-
- temp = value;
+ value = sens->therm.read(&sens->therm);
+ if (value < 0)
+ return (ENXIO);
- error = sysctl_handle_int(oidp, &temp, 0, req);
+ error = sysctl_handle_int(oidp, &value, 0, req);
return (error);
}
diff --git a/sys/dev/iicbus/ds1775.c b/sys/dev/iicbus/ds1775.c
index 0edc074..faa4a1a 100644
--- a/sys/dev/iicbus/ds1775.c
+++ b/sys/dev/iicbus/ds1775.c
@@ -49,33 +49,31 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
+#include <powerpc/powermac/powermac_thermal.h>
#define FCU_ZERO_C_TO_K 2732
/* Drivebay sensor: LM75/DS1775. */
#define DS1775_TEMP 0x0
-struct ds1775_sensor {
- char location[32];
-};
-
/* Regular bus attachment functions */
static int ds1775_probe(device_t);
static int ds1775_attach(device_t);
+struct ds1775_softc {
+ struct pmac_therm sc_sensor;
+ device_t sc_dev;
+ struct intr_config_hook enum_hook;
+ uint32_t sc_addr;
+};
+
/* Utility functions */
+static int ds1775_sensor_read(struct ds1775_softc *sc);
static int ds1775_sensor_sysctl(SYSCTL_HANDLER_ARGS);
static void ds1775_start(void *xdev);
static int ds1775_read_2(device_t dev, uint32_t addr, uint8_t reg,
uint16_t *data);
-struct ds1775_softc {
- device_t sc_dev;
- struct intr_config_hook enum_hook;
- uint32_t sc_addr;
- struct ds1775_sensor *sc_sensors;
-
-};
static device_method_t ds1775_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, ds1775_probe),
@@ -92,7 +90,6 @@ static driver_t ds1775_driver = {
static devclass_t ds1775_devclass;
DRIVER_MODULE(ds1755, iicbus, ds1775_driver, ds1775_devclass, 0, 0);
-MALLOC_DEFINE(M_DS1775, "ds1775", "Temp-Monitor DS1775");
static int
ds1775_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data)
@@ -169,7 +166,6 @@ ds1775_start(void *xdev)
{
phandle_t child;
struct ds1775_softc *sc;
- struct ds1775_sensor *sens;
struct sysctl_oid *sensroot_oid;
struct sysctl_ctx_list *ctx;
ssize_t plen;
@@ -183,30 +179,34 @@ ds1775_start(void *xdev)
child = ofw_bus_get_node(dev);
- sc->sc_sensors = malloc (sizeof(struct ds1775_sensor),
- M_DS1775, M_WAITOK | M_ZERO);
-
- sens = sc->sc_sensors;
-
ctx = device_get_sysctl_ctx(dev);
sensroot_oid = device_get_sysctl_tree(dev);
- plen = OF_getprop(child, "hwsensor-location", sens->location,
- sizeof(sens->location));
+ OF_getprop(child, "hwsensor-zone", &sc->sc_sensor.zone, sizeof(int));
+ plen = OF_getprop(child, "hwsensor-location", sc->sc_sensor.name,
+ sizeof(sc->sc_sensor.name));
units = "C";
if (plen == -1) {
strcpy(sysctl_name, "sensor");
} else {
- for (i = 0; i < strlen(sens->location); i++) {
- sysctl_name[i] = tolower(sens->location[i]);
+ for (i = 0; i < strlen(sc->sc_sensor.name); i++) {
+ sysctl_name[i] = tolower(sc->sc_sensor.name[i]);
if (isspace(sysctl_name[i]))
sysctl_name[i] = '_';
}
sysctl_name[i] = 0;
}
- sprintf(sysctl_desc,"%s (%s)", sens->location, units);
+ /* Make up target temperatures. These are low, for the drive bay. */
+ sc->sc_sensor.target_temp = 300 + FCU_ZERO_C_TO_K;
+ sc->sc_sensor.max_temp = 600 + FCU_ZERO_C_TO_K;
+
+ sc->sc_sensor.read =
+ (int (*)(struct pmac_therm *sc))(ds1775_sensor_read);
+ pmac_thermal_sensor_register(&sc->sc_sensor);
+
+ sprintf(sysctl_desc,"%s (%s)", sc->sc_sensor.name, units);
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sensroot_oid), OID_AUTO,
sysctl_name,
CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
@@ -216,14 +216,11 @@ ds1775_start(void *xdev)
}
static int
-ds1775_sensor_read(device_t dev, struct ds1775_sensor *sens, int *temp)
+ds1775_sensor_read(struct ds1775_softc *sc)
{
- struct ds1775_softc *sc;
uint16_t buf[2];
uint16_t read;
- sc = device_get_softc(dev);
-
ds1775_read_2(sc->sc_dev, sc->sc_addr, DS1775_TEMP, buf);
read = *((int16_t *)buf);
@@ -231,29 +228,21 @@ ds1775_sensor_read(device_t dev, struct ds1775_sensor *sens, int *temp)
/* The default mode of the ADC is 9 bit, the resolution is 0.5 C per
bit. The temperature is in tenth kelvin.
*/
- *temp = ((int16_t)(read) >> 7) * 5;
-
- return (0);
+ return (((int16_t)(read) >> 7) * 5 + FCU_ZERO_C_TO_K);
}
+
static int
ds1775_sensor_sysctl(SYSCTL_HANDLER_ARGS)
{
device_t dev;
struct ds1775_softc *sc;
- struct ds1775_sensor *sens;
- int value;
int error;
unsigned int temp;
dev = arg1;
sc = device_get_softc(dev);
- sens = &sc->sc_sensors[arg2];
-
- error = ds1775_sensor_read(dev, sens, &value);
- if (error != 0)
- return (error);
- temp = value + FCU_ZERO_C_TO_K;
+ temp = ds1775_sensor_read(sc);
error = sysctl_handle_int(oidp, &temp, 0, req);
diff --git a/sys/dev/iicbus/max6690.c b/sys/dev/iicbus/max6690.c
index cbfdc26..43d6c84 100644
--- a/sys/dev/iicbus/max6690.c
+++ b/sys/dev/iicbus/max6690.c
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
+#include <powerpc/powermac/powermac_thermal.h>
#define FCU_ZERO_C_TO_K 2732
@@ -61,8 +62,10 @@ __FBSDID("$FreeBSD$");
#define MAX6690_TEMP_MASK 0xe0
struct max6690_sensor {
+ struct pmac_therm therm;
+ device_t dev;
+
int id;
- char location[32];
};
/* Regular bus attachment functions */
@@ -70,6 +73,7 @@ static int max6690_probe(device_t);
static int max6690_attach(device_t);
/* Utility functions */
+static int max6690_sensor_read(struct max6690_sensor *sens);
static int max6690_sensor_sysctl(SYSCTL_HANDLER_ARGS);
static void max6690_start(void *xdev);
static int max6690_read_1(device_t dev, uint32_t addr, uint8_t reg,
@@ -167,7 +171,7 @@ max6690_fill_sensor_prop(device_t dev)
sizeof(location));
while (len < prop_len) {
if (sc->sc_sensors != NULL)
- strcpy(sc->sc_sensors[i].location, location + len);
+ strcpy(sc->sc_sensors[i].therm.name, location + len);
prev_len = strlen(location + len) + 1;
len += prev_len;
i++;
@@ -180,6 +184,22 @@ max6690_fill_sensor_prop(device_t dev)
for (j = 0; j < i; j++)
sc->sc_sensors[j].id = (id[j] & 0xf);
+ /* Fill the sensor zone property. */
+ prop_len = OF_getprop(child, "hwsensor-zone", id, sizeof(id));
+ for (j = 0; j < i; j++)
+ sc->sc_sensors[j].therm.zone = id[j];
+
+ /* Set up remaining sensor properties */
+ for (j = 0; j < i; j++) {
+ sc->sc_sensors[j].dev = dev;
+
+ sc->sc_sensors[j].therm.target_temp = 400 + 2732;
+ sc->sc_sensors[j].therm.max_temp = 800 + 2732;
+
+ sc->sc_sensors[j].therm.read =
+ (int (*)(struct pmac_therm *))(max6690_sensor_read);
+ }
+
return (i);
}
static int
@@ -240,10 +260,15 @@ max6690_start(void *xdev)
/* Now we can fill the properties into the allocated struct. */
sc->sc_nsensors = max6690_fill_sensor_prop(dev);
+ /* Register with powermac_thermal */
+ for (i = 0; i < sc->sc_nsensors; i++)
+ pmac_thermal_sensor_register(&sc->sc_sensors[i].therm);
+
/* Add sysctls for the sensors. */
for (i = 0; i < sc->sc_nsensors; i++) {
- for (j = 0; j < strlen(sc->sc_sensors[i].location); j++) {
- sysctl_name[j] = tolower(sc->sc_sensors[i].location[j]);
+ for (j = 0; j < strlen(sc->sc_sensors[i].therm.name); j++) {
+ sysctl_name[j] =
+ tolower(sc->sc_sensors[i].therm.name[j]);
if (isspace(sysctl_name[j]))
sysctl_name[j] = '_';
}
@@ -265,7 +290,7 @@ max6690_start(void *xdev)
device_printf(dev, "Sensors\n");
for (i = 0; i < sc->sc_nsensors; i++) {
device_printf(dev, "Location : %s ID: %d\n",
- sc->sc_sensors[i].location,
+ sc->sc_sensors[i].therm.name,
sc->sc_sensors[i].id);
}
}
@@ -274,14 +299,15 @@ max6690_start(void *xdev)
}
static int
-max6690_sensor_read(device_t dev, struct max6690_sensor *sens, int *temp)
+max6690_sensor_read(struct max6690_sensor *sens)
{
uint8_t reg_int = 0, reg_ext = 0;
uint8_t integer;
uint8_t fraction;
+ int temp;
struct max6690_softc *sc;
- sc = device_get_softc(dev);
+ sc = device_get_softc(sens->dev);
/* The internal sensor id's are even, the external ar odd. */
if ((sens->id % 2) == 0) {
@@ -301,9 +327,9 @@ max6690_sensor_read(device_t dev, struct max6690_sensor *sens, int *temp)
/* The temperature is in tenth kelvin, the fractional part resolution
is 0.125.
*/
- *temp = (integer * 10) + (fraction >> 5) * 10 / 8;
+ temp = (integer * 10) + (fraction >> 5) * 10 / 8;
- return (0);
+ return (temp);
}
static int
@@ -320,9 +346,9 @@ max6690_sensor_sysctl(SYSCTL_HANDLER_ARGS)
sc = device_get_softc(dev);
sens = &sc->sc_sensors[arg2];
- error = max6690_sensor_read(dev, sens, &value);
- if (error != 0)
- return (error);
+ value = max6690_sensor_read(sens);
+ if (value < 0)
+ return (EIO);
temp = value + FCU_ZERO_C_TO_K;
OpenPOWER on IntegriCloud