1239400Sandreast/*- 2239400Sandreast * Copyright (c) 2012 Andreas Tobler 3239400Sandreast * All rights reserved. 4239400Sandreast * 5239400Sandreast * Redistribution and use in source and binary forms, with or without 6239400Sandreast * modification, are permitted provided that the following conditions 7239400Sandreast * are met: 8239400Sandreast * 1. Redistributions of source code must retain the above copyright 9239400Sandreast * notice, this list of conditions and the following disclaimer. 10239400Sandreast * 2. Redistributions in binary form must reproduce the above copyright 11239400Sandreast * notice, this list of conditions and the following disclaimer in the 12239400Sandreast * documentation and/or other materials provided with the distribution. 13239400Sandreast * 14239400Sandreast * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15239400Sandreast * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16239400Sandreast * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17239400Sandreast * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18239400Sandreast * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19239400Sandreast * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20239400Sandreast * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21239400Sandreast * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22239400Sandreast * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23239400Sandreast * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24239400Sandreast * SUCH DAMAGE. 25239400Sandreast */ 26239400Sandreast 27239400Sandreast#include <sys/cdefs.h> 28239400Sandreast__FBSDID("$FreeBSD$"); 29239400Sandreast 30239400Sandreast#include <sys/param.h> 31239400Sandreast#include <sys/bus.h> 32239400Sandreast#include <sys/systm.h> 33239400Sandreast#include <sys/module.h> 34239400Sandreast#include <sys/callout.h> 35239400Sandreast#include <sys/conf.h> 36239400Sandreast#include <sys/cpu.h> 37239400Sandreast#include <sys/ctype.h> 38239400Sandreast#include <sys/kernel.h> 39239400Sandreast#include <sys/reboot.h> 40239400Sandreast#include <sys/rman.h> 41239400Sandreast#include <sys/sysctl.h> 42239400Sandreast#include <sys/limits.h> 43239400Sandreast 44239400Sandreast#include <machine/bus.h> 45239400Sandreast#include <machine/md_var.h> 46239400Sandreast 47239400Sandreast#include <dev/iicbus/iicbus.h> 48239400Sandreast#include <dev/iicbus/iiconf.h> 49239400Sandreast 50239400Sandreast#include <dev/ofw/openfirm.h> 51239400Sandreast#include <dev/ofw/ofw_bus.h> 52239400Sandreast#include <powerpc/powermac/powermac_thermal.h> 53239400Sandreast 54239400Sandreast/* Sensor: Maxim DS1631 */ 55239400Sandreast 56239400Sandreast#define DS1631_STOP 0x22 57239400Sandreast#define DS1631_START 0x51 58239400Sandreast#define DS1631_RESET 0x54 59239400Sandreast#define DS1631_TEMP 0xAA 60239400Sandreast#define DS1631_CONTROL 0xAC 61239400Sandreast#define DS1631_CONTROL_1SHOT 0x01 62239400Sandreast#define DS1631_CONTROL_9BIT 0x00 63239400Sandreast#define DS1631_CONTROL_10BIT 0x04 64239400Sandreast#define DS1631_CONTROL_11BIT 0x08 65239400Sandreast#define DS1631_CONTROL_12BIT 0x0C 66239400Sandreast 67239400Sandreast 68239400Sandreast 69239400Sandreast/* Regular bus attachment functions */ 70239400Sandreaststatic int ds1631_probe(device_t); 71239400Sandreaststatic int ds1631_attach(device_t); 72239400Sandreast 73239400Sandreaststruct ds1631_softc { 74239400Sandreast struct pmac_therm sc_sensor; 75239400Sandreast device_t sc_dev; 76239400Sandreast struct intr_config_hook enum_hook; 77239400Sandreast uint32_t sc_addr; 78239400Sandreast uint32_t init_done; 79239400Sandreast}; 80239400Sandreast 81239400Sandreaststruct write_data { 82239400Sandreast uint8_t reg; 83239400Sandreast uint8_t val; 84239400Sandreast}; 85239400Sandreast 86239400Sandreaststruct read_data { 87239400Sandreast uint8_t reg; 88239400Sandreast uint16_t val; 89239400Sandreast}; 90239400Sandreast 91239400Sandreast/* Utility functions */ 92239400Sandreaststatic int ds1631_sensor_read(struct ds1631_softc *sc); 93239400Sandreaststatic int ds1631_sensor_sysctl(SYSCTL_HANDLER_ARGS); 94239400Sandreaststatic void ds1631_start(void *xdev); 95239400Sandreaststatic int ds1631_read_1(device_t dev, uint32_t addr, uint8_t reg, 96239400Sandreast uint8_t *data); 97239400Sandreaststatic int ds1631_read_2(device_t dev, uint32_t addr, uint8_t reg, 98239400Sandreast uint16_t *data); 99239400Sandreaststatic int ds1631_write(device_t dev, uint32_t addr, uint8_t reg, 100239400Sandreast uint8_t *buff, int len); 101239400Sandreast 102239400Sandreaststatic device_method_t ds1631_methods[] = { 103239400Sandreast /* Device interface */ 104239400Sandreast DEVMETHOD(device_probe, ds1631_probe), 105239400Sandreast DEVMETHOD(device_attach, ds1631_attach), 106239400Sandreast { 0, 0 }, 107239400Sandreast}; 108239400Sandreast 109239400Sandreaststatic driver_t ds1631_driver = { 110239400Sandreast "ds1631", 111239400Sandreast ds1631_methods, 112239400Sandreast sizeof(struct ds1631_softc) 113239400Sandreast}; 114239400Sandreast 115239400Sandreaststatic devclass_t ds1631_devclass; 116239400Sandreast 117239400SandreastDRIVER_MODULE(ds1631, iicbus, ds1631_driver, ds1631_devclass, 0, 0); 118239400Sandreast 119239400Sandreaststatic int 120239400Sandreastds1631_write(device_t dev, uint32_t addr, uint8_t reg, uint8_t *buff, int len) 121239400Sandreast{ 122239400Sandreast uint8_t buf[4]; 123239400Sandreast int try = 0; 124239400Sandreast 125239400Sandreast struct iic_msg msg[] = { 126239400Sandreast { addr, IIC_M_WR, 0, buf } 127239400Sandreast }; 128239400Sandreast 129239400Sandreast /* Prepare the write msg. */ 130239400Sandreast msg[0].len = len + 1; 131239400Sandreast buf[0] = reg; 132239400Sandreast memcpy(buf + 1, buff, len); 133239400Sandreast 134239400Sandreast for (;;) 135239400Sandreast { 136239400Sandreast if (iicbus_transfer(dev, msg, 1) == 0) 137239400Sandreast return (0); 138239400Sandreast if (++try > 5) { 139239400Sandreast device_printf(dev, "iicbus write failed\n"); 140239400Sandreast return (-1); 141239400Sandreast } 142239400Sandreast pause("ds1631_write", hz); 143239400Sandreast } 144239400Sandreast} 145239400Sandreast 146239400Sandreaststatic int 147239400Sandreastds1631_read_1(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data) 148239400Sandreast{ 149239400Sandreast uint8_t buf[4]; 150239400Sandreast int err, try = 0; 151239400Sandreast 152239400Sandreast struct iic_msg msg[2] = { 153239400Sandreast { addr, IIC_M_WR, 1, ® }, 154239400Sandreast { addr, IIC_M_RD, 1, buf }, 155239400Sandreast }; 156239400Sandreast 157239400Sandreast for (;;) 158239400Sandreast { 159239400Sandreast err = iicbus_transfer(dev, msg, 2); 160239400Sandreast if (err != 0) 161239400Sandreast goto retry; 162239400Sandreast 163239400Sandreast *data = *((uint8_t*)buf); 164239400Sandreast return (0); 165239400Sandreast retry: 166239400Sandreast if (++try > 5) { 167239400Sandreast device_printf(dev, "iicbus read failed\n"); 168239400Sandreast return (-1); 169239400Sandreast } 170239400Sandreast pause("ds1631_read_1", hz); 171239400Sandreast } 172239400Sandreast} 173239400Sandreast 174239400Sandreaststatic int 175239400Sandreastds1631_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data) 176239400Sandreast{ 177239400Sandreast uint8_t buf[4]; 178239400Sandreast int err, try = 0; 179239400Sandreast 180239400Sandreast struct iic_msg msg[2] = { 181239400Sandreast { addr, IIC_M_WR, 1, ® }, 182239400Sandreast { addr, IIC_M_RD, 2, buf }, 183239400Sandreast }; 184239400Sandreast 185239400Sandreast for (;;) 186239400Sandreast { 187239400Sandreast err = iicbus_transfer(dev, msg, 2); 188239400Sandreast if (err != 0) 189239400Sandreast goto retry; 190239400Sandreast 191239400Sandreast *data = *((uint16_t*)buf); 192239400Sandreast return (0); 193239400Sandreast retry: 194239400Sandreast if (++try > 5) { 195239400Sandreast device_printf(dev, "iicbus read failed\n"); 196239400Sandreast return (-1); 197239400Sandreast } 198239400Sandreast pause("ds1631_read_2", hz); 199239400Sandreast } 200239400Sandreast} 201239400Sandreast 202239400Sandreaststatic int 203239400Sandreastds1631_probe(device_t dev) 204239400Sandreast{ 205239400Sandreast const char *name, *compatible; 206239400Sandreast struct ds1631_softc *sc; 207239400Sandreast 208239400Sandreast name = ofw_bus_get_name(dev); 209239400Sandreast compatible = ofw_bus_get_compat(dev); 210239400Sandreast 211239400Sandreast if (!name) 212239400Sandreast return (ENXIO); 213239400Sandreast 214239400Sandreast if (strcmp(name, "temp-monitor") != 0 || 215239400Sandreast strcmp(compatible, "ds1631") != 0 ) 216239400Sandreast return (ENXIO); 217239400Sandreast 218239400Sandreast sc = device_get_softc(dev); 219239400Sandreast sc->sc_dev = dev; 220239400Sandreast sc->sc_addr = iicbus_get_addr(dev); 221239400Sandreast 222239400Sandreast device_set_desc(dev, "Temp-Monitor DS1631"); 223239400Sandreast 224239400Sandreast return (0); 225239400Sandreast} 226239400Sandreast 227239400Sandreaststatic int 228239400Sandreastds1631_attach(device_t dev) 229239400Sandreast{ 230239400Sandreast struct ds1631_softc *sc; 231239400Sandreast 232239400Sandreast sc = device_get_softc(dev); 233239400Sandreast 234239400Sandreast sc->enum_hook.ich_func = ds1631_start; 235239400Sandreast sc->enum_hook.ich_arg = dev; 236239400Sandreast 237239400Sandreast /* 238239400Sandreast * We have to wait until interrupts are enabled. I2C read and write 239239400Sandreast * only works if the interrupts are available. 240239400Sandreast * The unin/i2c is controlled by the htpic on unin. But this is not 241239400Sandreast * the master. The openpic on mac-io is controlling the htpic. 242239400Sandreast * This one gets attached after the mac-io probing and then the 243239400Sandreast * interrupts will be available. 244239400Sandreast */ 245239400Sandreast 246239400Sandreast if (config_intrhook_establish(&sc->enum_hook) != 0) 247239400Sandreast return (ENOMEM); 248239400Sandreast 249239400Sandreast return (0); 250239400Sandreast} 251239400Sandreaststatic int 252239400Sandreastds1631_init(device_t dev, uint32_t addr) 253239400Sandreast{ 254239400Sandreast uint8_t conf; 255239400Sandreast int err; 256239400Sandreast struct ds1631_softc *sc; 257239400Sandreast 258239400Sandreast sc = device_get_softc(dev); 259239400Sandreast 260239400Sandreast err = ds1631_read_1(dev, addr, DS1631_CONTROL, &conf); 261239400Sandreast if (err < 0) { 262239400Sandreast device_printf(dev, "ds1631 read config failed: %x\n", err); 263239400Sandreast return (-1); 264239400Sandreast } 265239400Sandreast 266239400Sandreast /* Stop the conversion if not in 1SHOT mode. */ 267239400Sandreast if (conf & ~DS1631_CONTROL_1SHOT) 268239400Sandreast err = ds1631_write(dev, addr, DS1631_STOP, &conf, 0); 269239400Sandreast 270239400Sandreast /* 271239400Sandreast * Setup the resolution, 10-bit is enough. Each bit increase in 272239400Sandreast * resolution doubles the conversion time. 273239400Sandreast */ 274239400Sandreast conf = DS1631_CONTROL_10BIT; 275239400Sandreast 276239400Sandreast err = ds1631_write(dev, addr, DS1631_CONTROL, &conf, 1); 277239400Sandreast if (err < 0) { 278239400Sandreast device_printf(dev, "ds1631 write config failed: %x\n", err); 279239400Sandreast return (-1); 280239400Sandreast } 281239400Sandreast 282239400Sandreast /* And now start....*/ 283239400Sandreast err = ds1631_write(dev, addr, DS1631_START, &conf, 0); 284239400Sandreast 285239400Sandreast if (err < 0) { 286239400Sandreast device_printf(dev, "ds1631 write start failed: %x\n", err); 287239400Sandreast return (-1); 288239400Sandreast } 289239400Sandreast 290239400Sandreast sc->init_done = 1; 291239400Sandreast 292239400Sandreast return (0); 293239400Sandreast 294239400Sandreast} 295239400Sandreaststatic void 296239400Sandreastds1631_start(void *xdev) 297239400Sandreast{ 298239400Sandreast phandle_t child, node; 299239400Sandreast struct ds1631_softc *sc; 300239400Sandreast struct sysctl_oid *oid, *sensroot_oid; 301239400Sandreast struct sysctl_ctx_list *ctx; 302239400Sandreast ssize_t plen; 303239400Sandreast int i; 304239400Sandreast char sysctl_desc[40], sysctl_name[40]; 305239400Sandreast 306239400Sandreast device_t dev = (device_t)xdev; 307239400Sandreast 308239400Sandreast sc = device_get_softc(dev); 309239400Sandreast 310239400Sandreast child = ofw_bus_get_node(dev); 311239400Sandreast 312239400Sandreast ctx = device_get_sysctl_ctx(dev); 313239400Sandreast sensroot_oid = SYSCTL_ADD_NODE(ctx, 314239400Sandreast SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensor", 315239400Sandreast CTLFLAG_RD, 0, "DS1631 Sensor Information"); 316239400Sandreast 317239400Sandreast if (OF_getprop(child, "hwsensor-zone", &sc->sc_sensor.zone, 318239400Sandreast sizeof(int)) < 0) 319239400Sandreast sc->sc_sensor.zone = 0; 320239400Sandreast 321239400Sandreast plen = OF_getprop(child, "hwsensor-location", sc->sc_sensor.name, 322239400Sandreast sizeof(sc->sc_sensor.name)); 323239400Sandreast if (plen == -1) { 324239400Sandreast /* 325239400Sandreast * Ok, no hwsensor-location property, so let's look for a 326239400Sandreast * location property on a sub node. 327239400Sandreast */ 328239400Sandreast for (node = OF_child(child); node; node = OF_peer(node)) 329239400Sandreast plen = OF_getprop(node, "location", sc->sc_sensor.name, 330239400Sandreast sizeof(sc->sc_sensor.name)); 331239400Sandreast } 332239400Sandreast 333239400Sandreast if (plen == -1) { 334239400Sandreast strcpy(sysctl_name, "sensor"); 335239400Sandreast } else { 336239400Sandreast for (i = 0; i < strlen(sc->sc_sensor.name); i++) { 337239400Sandreast sysctl_name[i] = tolower(sc->sc_sensor.name[i]); 338239400Sandreast if (isspace(sysctl_name[i])) 339239400Sandreast sysctl_name[i] = '_'; 340239400Sandreast } 341239400Sandreast sysctl_name[i] = 0; 342239400Sandreast } 343239400Sandreast 344239400Sandreast /* Make up target temperatures. These are low, for the drive bay. */ 345239400Sandreast if (sc->sc_sensor.zone == 0) { 346239400Sandreast sc->sc_sensor.target_temp = 400 + ZERO_C_TO_K; 347239400Sandreast sc->sc_sensor.max_temp = 500 + ZERO_C_TO_K; 348239400Sandreast } else { 349239400Sandreast sc->sc_sensor.target_temp = 300 + ZERO_C_TO_K; 350239400Sandreast sc->sc_sensor.max_temp = 500 + ZERO_C_TO_K; 351239400Sandreast } 352239400Sandreast 353239400Sandreast sc->sc_sensor.read = 354239400Sandreast (int (*)(struct pmac_therm *sc))(ds1631_sensor_read); 355239400Sandreast pmac_thermal_sensor_register(&sc->sc_sensor); 356239400Sandreast 357239400Sandreast sprintf(sysctl_desc,"%s %s", sc->sc_sensor.name, "(C)"); 358239400Sandreast oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(sensroot_oid), 359239400Sandreast OID_AUTO, sysctl_name, CTLFLAG_RD, 0, 360239400Sandreast "Sensor Information"); 361239400Sandreast SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "temp", 362239400Sandreast CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, 363239400Sandreast 0, ds1631_sensor_sysctl, "IK", sysctl_desc); 364239400Sandreast 365239400Sandreast config_intrhook_disestablish(&sc->enum_hook); 366239400Sandreast} 367239400Sandreast 368239400Sandreaststatic int 369239400Sandreastds1631_sensor_read(struct ds1631_softc *sc) 370239400Sandreast{ 371239400Sandreast uint16_t buf[2]; 372239400Sandreast uint16_t read; 373239400Sandreast int err; 374239400Sandreast 375239400Sandreast if (!sc->init_done) 376239400Sandreast ds1631_init(sc->sc_dev, sc->sc_addr); 377239400Sandreast 378239400Sandreast err = ds1631_read_2(sc->sc_dev, sc->sc_addr, DS1631_TEMP, buf); 379239400Sandreast if (err < 0) { 380239400Sandreast device_printf(sc->sc_dev, "ds1631 read TEMP failed: %x\n", err); 381239400Sandreast return (-1); 382239400Sandreast } 383239400Sandreast 384239400Sandreast read = *((int16_t *)buf); 385239400Sandreast 386239400Sandreast /* 387239400Sandreast * The default mode of the ADC is 12-bit, the resolution is 0.0625 C 388239400Sandreast * per bit. The temperature is in tenth kelvin. 389239400Sandreast * We use 10-bit resolution which seems enough, resolution is 0.25 C. 390239400Sandreast */ 391239400Sandreast 392239400Sandreast return (((int16_t)(read) >> 6) * 25 / 10 + ZERO_C_TO_K); 393239400Sandreast} 394239400Sandreast 395239400Sandreaststatic int 396239400Sandreastds1631_sensor_sysctl(SYSCTL_HANDLER_ARGS) 397239400Sandreast{ 398239400Sandreast device_t dev; 399239400Sandreast struct ds1631_softc *sc; 400239400Sandreast int error; 401239400Sandreast unsigned int temp; 402239400Sandreast 403239400Sandreast dev = arg1; 404239400Sandreast sc = device_get_softc(dev); 405239400Sandreast 406239400Sandreast temp = ds1631_sensor_read(sc); 407239400Sandreast if (temp < 0) 408239400Sandreast return (EIO); 409239400Sandreast 410239400Sandreast error = sysctl_handle_int(oidp, &temp, 0, req); 411239400Sandreast 412239400Sandreast return (error); 413239400Sandreast} 414