1 /* $OpenBSD: ds1631.c,v 1.11 2009/08/12 17:13:30 kettenis Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Theo de Raadt 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/device.h> 22 #include <sys/sensors.h> 23 24 #include <dev/i2c/i2cvar.h> 25 26 /* Maxim ds 1631 registers */ 27 #define DS1631_START 0x51 28 #define DS1624_START 0xee 29 #define DS1631_TEMP 0xaa 30 #define DS1631_CONTROL 0xac 31 #define DS1631_CONTROL_DONE 0x80 32 #define DS1631_CONTROL_1SHOT 0x01 33 34 /* Sensors */ 35 #define MAXDS_TEMP 0 36 #define MAXDS_NUM_SENSORS 1 37 38 struct maxds_softc { 39 struct device sc_dev; 40 i2c_tag_t sc_tag; 41 i2c_addr_t sc_addr; 42 43 struct ksensor sc_sensor[MAXDS_NUM_SENSORS]; 44 struct ksensordev sc_sensordev; 45 }; 46 47 int maxds_match(struct device *, void *, void *); 48 void maxds_attach(struct device *, struct device *, void *); 49 void maxds_refresh(void *); 50 51 struct cfattach maxds_ca = { 52 sizeof(struct maxds_softc), maxds_match, maxds_attach 53 }; 54 55 struct cfdriver maxds_cd = { 56 NULL, "maxds", DV_DULL 57 }; 58 59 int 60 maxds_match(struct device *parent, void *match, void *aux) 61 { 62 struct i2c_attach_args *ia = aux; 63 64 if (strcmp(ia->ia_name, "ds1631") == 0 || 65 strcmp(ia->ia_name, "ds1624") == 0 || 66 strcmp(ia->ia_name, "ds1721") == 0) 67 return (1); 68 return (0); 69 } 70 71 void 72 maxds_attach(struct device *parent, struct device *self, void *aux) 73 { 74 struct maxds_softc *sc = (struct maxds_softc *)self; 75 struct i2c_attach_args *ia = aux; 76 u_int8_t cmd, data; 77 int i; 78 79 printf(": %s", ia->ia_name); 80 81 sc->sc_tag = ia->ia_tag; 82 sc->sc_addr = ia->ia_addr; 83 84 iic_acquire_bus(sc->sc_tag, 0); 85 86 cmd = DS1631_CONTROL; 87 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 88 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0) { 89 if (data & DS1631_CONTROL_1SHOT) { 90 /* 91 * 1-Shot mode would require us to write every refresh 92 * which is stupid. Put us into continuous mode. 93 */ 94 data &= ~DS1631_CONTROL_1SHOT; 95 96 (void) iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 97 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0); 98 //delay(10 * 1000); 99 printf(", continuous"); 100 goto dostart; 101 } 102 if (data & DS1631_CONTROL_DONE) { 103 dostart: 104 cmd = DS1631_START; 105 if (strcmp(ia->ia_name, "ds1624") == 0) 106 cmd = DS1624_START; 107 (void) iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 108 sc->sc_addr, &cmd, sizeof cmd, NULL, 0, 0); 109 printf(", starting"); 110 } 111 } 112 113 iic_release_bus(sc->sc_tag, 0); 114 115 /* Initialize sensor data. */ 116 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 117 sizeof(sc->sc_sensordev.xname)); 118 119 sc->sc_sensor[MAXDS_TEMP].type = SENSOR_TEMP; 120 strlcpy(sc->sc_sensor[MAXDS_TEMP].desc, "Internal", 121 sizeof(sc->sc_sensor[MAXDS_TEMP].desc)); 122 123 if (sensor_task_register(sc, maxds_refresh, 5) == NULL) { 124 printf(", unable to register update task\n"); 125 return; 126 } 127 128 for (i = 0; i < MAXDS_NUM_SENSORS; i++) 129 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]); 130 sensordev_install(&sc->sc_sensordev); 131 132 printf("\n"); 133 } 134 135 void 136 maxds_refresh(void *arg) 137 { 138 struct maxds_softc *sc = arg; 139 u_int8_t cmd; 140 u_int16_t data; 141 142 iic_acquire_bus(sc->sc_tag, 0); 143 144 cmd = DS1631_TEMP; 145 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 146 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0) == 0) { 147 sc->sc_sensor[MAXDS_TEMP].value = 273150000 + 148 (int)(betoh16(data)) / 8 * 31250; 149 sc->sc_sensor[MAXDS_TEMP].flags &= ~SENSOR_FINVALID; 150 } else 151 sc->sc_sensor[MAXDS_TEMP].flags |= SENSOR_FINVALID; 152 153 iic_release_bus(sc->sc_tag, 0); 154 } 155