ds1775.c revision 217560
1213904Sandreast/*- 2213904Sandreast * Copyright (c) 2010 Andreas Tobler 3213904Sandreast * All rights reserved. 4213904Sandreast * 5213904Sandreast * Redistribution and use in source and binary forms, with or without 6213904Sandreast * modification, are permitted provided that the following conditions 7213904Sandreast * are met: 8213904Sandreast * 1. Redistributions of source code must retain the above copyright 9213904Sandreast * notice, this list of conditions and the following disclaimer. 10213904Sandreast * 2. Redistributions in binary form must reproduce the above copyright 11213904Sandreast * notice, this list of conditions and the following disclaimer in the 12213904Sandreast * documentation and/or other materials provided with the distribution. 13213904Sandreast * 14213904Sandreast * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15213904Sandreast * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16213904Sandreast * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17213904Sandreast * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18213904Sandreast * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19213904Sandreast * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20213904Sandreast * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21213904Sandreast * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22213904Sandreast * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23213904Sandreast * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24213904Sandreast * SUCH DAMAGE. 25213904Sandreast */ 26213904Sandreast 27213904Sandreast#include <sys/cdefs.h> 28213904Sandreast__FBSDID("$FreeBSD: head/sys/dev/iicbus/ds1775.c 217560 2011-01-18 21:47:30Z andreast $"); 29213904Sandreast 30213904Sandreast#include <sys/param.h> 31213904Sandreast#include <sys/bus.h> 32213904Sandreast#include <sys/systm.h> 33213904Sandreast#include <sys/module.h> 34213904Sandreast#include <sys/callout.h> 35213904Sandreast#include <sys/conf.h> 36213904Sandreast#include <sys/cpu.h> 37213904Sandreast#include <sys/ctype.h> 38213904Sandreast#include <sys/kernel.h> 39213904Sandreast#include <sys/reboot.h> 40213904Sandreast#include <sys/rman.h> 41213904Sandreast#include <sys/sysctl.h> 42213904Sandreast#include <sys/limits.h> 43213904Sandreast 44213904Sandreast#include <machine/bus.h> 45213904Sandreast#include <machine/md_var.h> 46213904Sandreast 47213904Sandreast#include <dev/iicbus/iicbus.h> 48213904Sandreast#include <dev/iicbus/iiconf.h> 49213904Sandreast 50213904Sandreast#include <dev/ofw/openfirm.h> 51213904Sandreast#include <dev/ofw/ofw_bus.h> 52213904Sandreast 53213904Sandreast#define FCU_ZERO_C_TO_K 2732 54213904Sandreast 55213904Sandreast/* Drivebay sensor: LM75/DS1775. */ 56213904Sandreast#define DS1775_TEMP 0x0 57213904Sandreast 58213904Sandreaststruct ds1775_sensor { 59213904Sandreast char location[32]; 60213904Sandreast}; 61213904Sandreast 62213904Sandreast/* Regular bus attachment functions */ 63213904Sandreaststatic int ds1775_probe(device_t); 64213904Sandreaststatic int ds1775_attach(device_t); 65213904Sandreast 66213904Sandreast/* Utility functions */ 67213904Sandreaststatic int ds1775_sensor_sysctl(SYSCTL_HANDLER_ARGS); 68213904Sandreaststatic void ds1775_start(void *xdev); 69213904Sandreaststatic int ds1775_read_2(device_t dev, uint32_t addr, uint8_t reg, 70213904Sandreast uint16_t *data); 71213904Sandreast 72213904Sandreaststruct ds1775_softc { 73213904Sandreast device_t sc_dev; 74213904Sandreast struct intr_config_hook enum_hook; 75213904Sandreast uint32_t sc_addr; 76213904Sandreast struct ds1775_sensor *sc_sensors; 77213904Sandreast 78213904Sandreast}; 79213904Sandreaststatic device_method_t ds1775_methods[] = { 80213904Sandreast /* Device interface */ 81213904Sandreast DEVMETHOD(device_probe, ds1775_probe), 82213904Sandreast DEVMETHOD(device_attach, ds1775_attach), 83213904Sandreast { 0, 0 }, 84213904Sandreast}; 85213904Sandreast 86213904Sandreaststatic driver_t ds1775_driver = { 87213904Sandreast "ds1775", 88213904Sandreast ds1775_methods, 89213904Sandreast sizeof(struct ds1775_softc) 90213904Sandreast}; 91213904Sandreast 92213904Sandreaststatic devclass_t ds1775_devclass; 93213904Sandreast 94213904SandreastDRIVER_MODULE(ds1755, iicbus, ds1775_driver, ds1775_devclass, 0, 0); 95213904SandreastMALLOC_DEFINE(M_DS1775, "ds1775", "Temp-Monitor DS1775"); 96213904Sandreast 97213904Sandreaststatic int 98213904Sandreastds1775_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data) 99213904Sandreast{ 100213904Sandreast uint8_t buf[4]; 101213904Sandreast 102213904Sandreast struct iic_msg msg[2] = { 103213904Sandreast { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, 104213904Sandreast { addr, IIC_M_RD, 2, buf }, 105213904Sandreast }; 106213904Sandreast 107213904Sandreast if (iicbus_transfer(dev, msg, 2) != 0) { 108213904Sandreast device_printf(dev, "iicbus read failed\n"); 109213904Sandreast return (EIO); 110213904Sandreast } 111213904Sandreast 112213904Sandreast *data = *((uint16_t*)buf); 113213904Sandreast 114213904Sandreast return (0); 115213904Sandreast} 116213904Sandreast 117213904Sandreaststatic int 118213904Sandreastds1775_probe(device_t dev) 119213904Sandreast{ 120213904Sandreast const char *name, *compatible; 121213904Sandreast struct ds1775_softc *sc; 122213904Sandreast 123213904Sandreast name = ofw_bus_get_name(dev); 124213904Sandreast compatible = ofw_bus_get_compat(dev); 125213904Sandreast 126213904Sandreast if (!name) 127213904Sandreast return (ENXIO); 128213904Sandreast 129213904Sandreast if (strcmp(name, "temp-monitor") != 0 || 130216360Sandreast (strcmp(compatible, "ds1775") != 0 && 131216360Sandreast strcmp(compatible, "lm75") != 0)) 132213904Sandreast return (ENXIO); 133213904Sandreast 134213904Sandreast sc = device_get_softc(dev); 135213904Sandreast sc->sc_dev = dev; 136213904Sandreast sc->sc_addr = iicbus_get_addr(dev); 137213904Sandreast 138216360Sandreast device_set_desc(dev, "Temp-Monitor DS1775"); 139213904Sandreast 140213904Sandreast return (0); 141213904Sandreast} 142213904Sandreast 143213904Sandreaststatic int 144213904Sandreastds1775_attach(device_t dev) 145213904Sandreast{ 146213904Sandreast struct ds1775_softc *sc; 147213904Sandreast 148213904Sandreast sc = device_get_softc(dev); 149213904Sandreast 150213904Sandreast sc->enum_hook.ich_func = ds1775_start; 151213904Sandreast sc->enum_hook.ich_arg = dev; 152213904Sandreast 153213904Sandreast /* We have to wait until interrupts are enabled. I2C read and write 154213904Sandreast * only works if the interrupts are available. 155213904Sandreast * The unin/i2c is controlled by the htpic on unin. But this is not 156213904Sandreast * the master. The openpic on mac-io is controlling the htpic. 157213904Sandreast * This one gets attached after the mac-io probing and then the 158213904Sandreast * interrupts will be available. 159213904Sandreast */ 160213904Sandreast 161213904Sandreast if (config_intrhook_establish(&sc->enum_hook) != 0) 162213904Sandreast return (ENOMEM); 163213904Sandreast 164213904Sandreast return (0); 165213904Sandreast} 166213904Sandreast 167213904Sandreaststatic void 168213904Sandreastds1775_start(void *xdev) 169213904Sandreast{ 170213904Sandreast phandle_t child; 171213904Sandreast struct ds1775_softc *sc; 172213904Sandreast struct ds1775_sensor *sens; 173213904Sandreast struct sysctl_oid *sensroot_oid; 174213904Sandreast struct sysctl_ctx_list *ctx; 175217560Sandreast ssize_t plen; 176213904Sandreast int i; 177213904Sandreast char sysctl_name[40], sysctl_desc[40]; 178213904Sandreast const char *units; 179213904Sandreast 180213904Sandreast device_t dev = (device_t)xdev; 181213904Sandreast 182213904Sandreast sc = device_get_softc(dev); 183213904Sandreast 184213904Sandreast child = ofw_bus_get_node(dev); 185213904Sandreast 186213904Sandreast sc->sc_sensors = malloc (sizeof(struct ds1775_sensor), 187213904Sandreast M_DS1775, M_WAITOK | M_ZERO); 188213904Sandreast 189213904Sandreast sens = sc->sc_sensors; 190213904Sandreast 191213904Sandreast ctx = device_get_sysctl_ctx(dev); 192213904Sandreast sensroot_oid = device_get_sysctl_tree(dev); 193213904Sandreast 194217560Sandreast plen = OF_getprop(child, "hwsensor-location", sens->location, 195217560Sandreast sizeof(sens->location)); 196213904Sandreast units = "C"; 197213904Sandreast 198217560Sandreast if (plen == -1) { 199217560Sandreast strcpy(sysctl_name, "sensor"); 200217560Sandreast } else { 201217560Sandreast for (i = 0; i < strlen(sens->location); i++) { 202217560Sandreast sysctl_name[i] = tolower(sens->location[i]); 203217560Sandreast if (isspace(sysctl_name[i])) 204217560Sandreast sysctl_name[i] = '_'; 205217560Sandreast } 206217560Sandreast sysctl_name[i] = 0; 207213904Sandreast } 208213904Sandreast 209213904Sandreast sprintf(sysctl_desc,"%s (%s)", sens->location, units); 210213904Sandreast SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sensroot_oid), OID_AUTO, 211213904Sandreast sysctl_name, 212213904Sandreast CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, 213213904Sandreast 0, ds1775_sensor_sysctl, "IK", sysctl_desc); 214213904Sandreast 215213904Sandreast config_intrhook_disestablish(&sc->enum_hook); 216213904Sandreast} 217213904Sandreast 218213904Sandreaststatic int 219213904Sandreastds1775_sensor_read(device_t dev, struct ds1775_sensor *sens, int *temp) 220213904Sandreast{ 221213904Sandreast struct ds1775_softc *sc; 222213904Sandreast uint16_t buf[2]; 223213904Sandreast uint16_t read; 224213904Sandreast 225213904Sandreast sc = device_get_softc(dev); 226213904Sandreast 227213904Sandreast ds1775_read_2(sc->sc_dev, sc->sc_addr, DS1775_TEMP, buf); 228213904Sandreast 229213904Sandreast read = *((int16_t *)buf); 230213904Sandreast 231213904Sandreast /* The default mode of the ADC is 9 bit, the resolution is 0.5 C per 232213904Sandreast bit. The temperature is in tenth kelvin. 233213904Sandreast */ 234213904Sandreast *temp = ((int16_t)(read) >> 7) * 5; 235213904Sandreast 236213904Sandreast return (0); 237213904Sandreast} 238213904Sandreaststatic int 239213904Sandreastds1775_sensor_sysctl(SYSCTL_HANDLER_ARGS) 240213904Sandreast{ 241213904Sandreast device_t dev; 242213904Sandreast struct ds1775_softc *sc; 243213904Sandreast struct ds1775_sensor *sens; 244213904Sandreast int value; 245213904Sandreast int error; 246213904Sandreast unsigned int temp; 247213904Sandreast 248213904Sandreast dev = arg1; 249213904Sandreast sc = device_get_softc(dev); 250213904Sandreast sens = &sc->sc_sensors[arg2]; 251213904Sandreast 252213904Sandreast error = ds1775_sensor_read(dev, sens, &value); 253213904Sandreast if (error != 0) 254213904Sandreast return (error); 255213904Sandreast 256213904Sandreast temp = value + FCU_ZERO_C_TO_K; 257213904Sandreast 258213904Sandreast error = sysctl_handle_int(oidp, &temp, 0, req); 259213904Sandreast 260213904Sandreast return (error); 261213904Sandreast} 262