ds1775.c revision 213904
1/*- 2 * Copyright (c) 2010 Andreas Tobler 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/dev/iicbus/ds1775.c 213904 2010-10-15 20:08:16Z andreast $"); 29 30#include <sys/param.h> 31#include <sys/bus.h> 32#include <sys/systm.h> 33#include <sys/module.h> 34#include <sys/callout.h> 35#include <sys/conf.h> 36#include <sys/cpu.h> 37#include <sys/ctype.h> 38#include <sys/kernel.h> 39#include <sys/reboot.h> 40#include <sys/rman.h> 41#include <sys/sysctl.h> 42#include <sys/limits.h> 43 44#include <machine/bus.h> 45#include <machine/md_var.h> 46 47#include <dev/iicbus/iicbus.h> 48#include <dev/iicbus/iiconf.h> 49 50#include <dev/ofw/openfirm.h> 51#include <dev/ofw/ofw_bus.h> 52 53#define FCU_ZERO_C_TO_K 2732 54 55/* Drivebay sensor: LM75/DS1775. */ 56#define DS1775_TEMP 0x0 57 58struct ds1775_sensor { 59 char location[32]; 60}; 61 62/* Regular bus attachment functions */ 63static int ds1775_probe(device_t); 64static int ds1775_attach(device_t); 65 66/* Utility functions */ 67static int ds1775_sensor_sysctl(SYSCTL_HANDLER_ARGS); 68static void ds1775_start(void *xdev); 69static int ds1775_read_2(device_t dev, uint32_t addr, uint8_t reg, 70 uint16_t *data); 71 72struct ds1775_softc { 73 device_t sc_dev; 74 struct intr_config_hook enum_hook; 75 uint32_t sc_addr; 76 struct ds1775_sensor *sc_sensors; 77 78}; 79static device_method_t ds1775_methods[] = { 80 /* Device interface */ 81 DEVMETHOD(device_probe, ds1775_probe), 82 DEVMETHOD(device_attach, ds1775_attach), 83 { 0, 0 }, 84}; 85 86static driver_t ds1775_driver = { 87 "ds1775", 88 ds1775_methods, 89 sizeof(struct ds1775_softc) 90}; 91 92static devclass_t ds1775_devclass; 93 94DRIVER_MODULE(ds1755, iicbus, ds1775_driver, ds1775_devclass, 0, 0); 95MALLOC_DEFINE(M_DS1775, "ds1775", "Temp-Monitor DS1775"); 96 97static int 98ds1775_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data) 99{ 100 uint8_t buf[4]; 101 102 struct iic_msg msg[2] = { 103 { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, 104 { addr, IIC_M_RD, 2, buf }, 105 }; 106 107 if (iicbus_transfer(dev, msg, 2) != 0) { 108 device_printf(dev, "iicbus read failed\n"); 109 return (EIO); 110 } 111 112 *data = *((uint16_t*)buf); 113 114 return (0); 115} 116 117static int 118ds1775_probe(device_t dev) 119{ 120 const char *name, *compatible; 121 struct ds1775_softc *sc; 122 123 name = ofw_bus_get_name(dev); 124 compatible = ofw_bus_get_compat(dev); 125 126 if (!name) 127 return (ENXIO); 128 129 if (strcmp(name, "temp-monitor") != 0 || 130 strcmp(compatible, "ds1775") != 0) 131 return (ENXIO); 132 133 sc = device_get_softc(dev); 134 sc->sc_dev = dev; 135 sc->sc_addr = iicbus_get_addr(dev); 136 137 device_set_desc(dev, "Temp-Monitor DS1755"); 138 139 return (0); 140} 141 142static int 143ds1775_attach(device_t dev) 144{ 145 struct ds1775_softc *sc; 146 147 sc = device_get_softc(dev); 148 149 sc->enum_hook.ich_func = ds1775_start; 150 sc->enum_hook.ich_arg = dev; 151 152 /* We have to wait until interrupts are enabled. I2C read and write 153 * only works if the interrupts are available. 154 * The unin/i2c is controlled by the htpic on unin. But this is not 155 * the master. The openpic on mac-io is controlling the htpic. 156 * This one gets attached after the mac-io probing and then the 157 * interrupts will be available. 158 */ 159 160 if (config_intrhook_establish(&sc->enum_hook) != 0) 161 return (ENOMEM); 162 163 return (0); 164} 165 166static void 167ds1775_start(void *xdev) 168{ 169 phandle_t child; 170 struct ds1775_softc *sc; 171 struct ds1775_sensor *sens; 172 struct sysctl_oid *sensroot_oid; 173 struct sysctl_ctx_list *ctx; 174 int i; 175 char sysctl_name[40], sysctl_desc[40]; 176 const char *units; 177 178 device_t dev = (device_t)xdev; 179 180 sc = device_get_softc(dev); 181 182 child = ofw_bus_get_node(dev); 183 184 sc->sc_sensors = malloc (sizeof(struct ds1775_sensor), 185 M_DS1775, M_WAITOK | M_ZERO); 186 187 sens = sc->sc_sensors; 188 189 ctx = device_get_sysctl_ctx(dev); 190 sensroot_oid = device_get_sysctl_tree(dev); 191 192 OF_getprop(child, "hwsensor-location", sens->location, 193 sizeof(sens->location)); 194 units = "C"; 195 196 for (i = 0; i < strlen(sens->location); i++) { 197 sysctl_name[i] = tolower(sens->location[i]); 198 if (isspace(sysctl_name[i])) 199 sysctl_name[i] = '_'; 200 } 201 sysctl_name[i] = 0; 202 203 sprintf(sysctl_desc,"%s (%s)", sens->location, units); 204 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sensroot_oid), OID_AUTO, 205 sysctl_name, 206 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, 207 0, ds1775_sensor_sysctl, "IK", sysctl_desc); 208 209 config_intrhook_disestablish(&sc->enum_hook); 210} 211 212static int 213ds1775_sensor_read(device_t dev, struct ds1775_sensor *sens, int *temp) 214{ 215 struct ds1775_softc *sc; 216 uint16_t buf[2]; 217 uint16_t read; 218 219 sc = device_get_softc(dev); 220 221 ds1775_read_2(sc->sc_dev, sc->sc_addr, DS1775_TEMP, buf); 222 223 read = *((int16_t *)buf); 224 225 /* The default mode of the ADC is 9 bit, the resolution is 0.5 C per 226 bit. The temperature is in tenth kelvin. 227 */ 228 *temp = ((int16_t)(read) >> 7) * 5; 229 230 return (0); 231} 232static int 233ds1775_sensor_sysctl(SYSCTL_HANDLER_ARGS) 234{ 235 device_t dev; 236 struct ds1775_softc *sc; 237 struct ds1775_sensor *sens; 238 int value; 239 int error; 240 unsigned int temp; 241 242 dev = arg1; 243 sc = device_get_softc(dev); 244 sens = &sc->sc_sensors[arg2]; 245 246 error = ds1775_sensor_read(dev, sens, &value); 247 if (error != 0) 248 return (error); 249 250 temp = value + FCU_ZERO_C_TO_K; 251 252 error = sysctl_handle_int(oidp, &temp, 0, req); 253 254 return (error); 255} 256