root/dev/onewire/owtemp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. owtemp_match
  2. owtemp_attach
  3. owtemp_detach
  4. owtemp_activate
  5. owtemp_update

    1 /*      $OpenBSD: owtemp.c,v 1.8 2007/06/24 05:34:35 dlg Exp $  */
    2 
    3 /*
    4  * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org>
    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 /*
   20  * 1-Wire temperature family type device driver.
   21  */
   22 
   23 #include <sys/param.h>
   24 #include <sys/systm.h>
   25 #include <sys/device.h>
   26 #include <sys/kernel.h>
   27 #include <sys/proc.h>
   28 #include <sys/rwlock.h>
   29 #include <sys/sensors.h>
   30 
   31 #include <dev/onewire/onewiredevs.h>
   32 #include <dev/onewire/onewirereg.h>
   33 #include <dev/onewire/onewirevar.h>
   34 
   35 /* Commands */
   36 #define DS1920_CMD_CONVERT              0x44
   37 #define DS1920_CMD_READ_SCRATCHPAD      0xbe
   38 
   39 /* Scratchpad layout */
   40 #define DS1920_SP_TEMP_LSB              0
   41 #define DS1920_SP_TEMP_MSB              1
   42 #define DS1920_SP_TH                    2
   43 #define DS1920_SP_TL                    3
   44 #define DS1920_SP_COUNT_REMAIN          6
   45 #define DS1920_SP_COUNT_PERC            7
   46 #define DS1920_SP_CRC                   8
   47 
   48 struct owtemp_softc {
   49         struct device           sc_dev;
   50 
   51         void *                  sc_onewire;
   52         u_int64_t               sc_rom;
   53 
   54         struct ksensor          sc_sensor;
   55         struct ksensordev       sc_sensordev;
   56         struct sensor_task      *sc_sensortask;
   57         struct rwlock           sc_lock;
   58 };
   59 
   60 int     owtemp_match(struct device *, void *, void *);
   61 void    owtemp_attach(struct device *, struct device *, void *);
   62 int     owtemp_detach(struct device *, int);
   63 int     owtemp_activate(struct device *, enum devact);
   64 
   65 void    owtemp_update(void *);
   66 
   67 struct cfattach owtemp_ca = {
   68         sizeof(struct owtemp_softc),
   69         owtemp_match,
   70         owtemp_attach,
   71         owtemp_detach,
   72         owtemp_activate
   73 };
   74 
   75 struct cfdriver owtemp_cd = {
   76         NULL, "owtemp", DV_DULL
   77 };
   78 
   79 static const struct onewire_matchfam owtemp_fams[] = {
   80         { ONEWIRE_FAMILY_DS1920 }
   81 };
   82 
   83 int
   84 owtemp_match(struct device *parent, void *match, void *aux)
   85 {
   86         return (onewire_matchbyfam(aux, owtemp_fams,
   87             sizeof(owtemp_fams) /sizeof(owtemp_fams[0])));
   88 }
   89 
   90 void
   91 owtemp_attach(struct device *parent, struct device *self, void *aux)
   92 {
   93         struct owtemp_softc *sc = (struct owtemp_softc *)self;
   94         struct onewire_attach_args *oa = aux;
   95 
   96         sc->sc_onewire = oa->oa_onewire;
   97         sc->sc_rom = oa->oa_rom;
   98 
   99         /* Initialize sensor */
  100         strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
  101             sizeof(sc->sc_sensordev.xname));
  102         sc->sc_sensor.type = SENSOR_TEMP;
  103 
  104         sc->sc_sensortask = sensor_task_register(sc, owtemp_update, 5);
  105         if (sc->sc_sensortask == NULL) {
  106                 printf(": unable to register update task\n");
  107                 return;
  108         }
  109         sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
  110         sensordev_install(&sc->sc_sensordev);
  111 
  112         rw_init(&sc->sc_lock, sc->sc_dev.dv_xname);
  113         printf("\n");
  114 }
  115 
  116 int
  117 owtemp_detach(struct device *self, int flags)
  118 {
  119         struct owtemp_softc *sc = (struct owtemp_softc *)self;
  120 
  121         rw_enter_write(&sc->sc_lock);
  122         sensordev_deinstall(&sc->sc_sensordev);
  123         if (sc->sc_sensortask != NULL)
  124                 sensor_task_unregister(sc->sc_sensortask);
  125         rw_exit_write(&sc->sc_lock);
  126 
  127         return (0);
  128 }
  129 
  130 int
  131 owtemp_activate(struct device *self, enum devact act)
  132 {
  133         return (0);
  134 }
  135 
  136 void
  137 owtemp_update(void *arg)
  138 {
  139         struct owtemp_softc *sc = arg;
  140         u_int8_t data[9];
  141         u_int16_t temp;
  142         int count_perc, count_remain, val;
  143 
  144         rw_enter_write(&sc->sc_lock);
  145         onewire_lock(sc->sc_onewire, 0);
  146         if (onewire_reset(sc->sc_onewire) != 0)
  147                 goto done;
  148         onewire_matchrom(sc->sc_onewire, sc->sc_rom);
  149 
  150         /*
  151          * Start temperature conversion. The conversion takes up to 750ms.
  152          * After sending the command, the data line must be held high for
  153          * at least 750ms to provide power during the conversion process.
  154          * As such, no other activity may take place on the 1-Wire bus for
  155          * at least this period.
  156          */
  157         onewire_write_byte(sc->sc_onewire, DS1920_CMD_CONVERT);
  158         tsleep(sc, PRIBIO, "owtemp", hz);
  159 
  160         if (onewire_reset(sc->sc_onewire) != 0)
  161                 goto done;
  162         onewire_matchrom(sc->sc_onewire, sc->sc_rom);
  163 
  164         /*
  165          * The result of the temperature measurement is placed in the
  166          * first two bytes of the scratchpad.
  167          */
  168         onewire_write_byte(sc->sc_onewire, DS1920_CMD_READ_SCRATCHPAD);
  169         onewire_read_block(sc->sc_onewire, data, 9);
  170         if (onewire_crc(data, 8) == data[DS1920_SP_CRC]) {
  171                 temp = data[DS1920_SP_TEMP_MSB] << 8 |
  172                     data[DS1920_SP_TEMP_LSB];
  173                 count_perc = data[DS1920_SP_COUNT_PERC];
  174                 count_remain = data[DS1920_SP_COUNT_REMAIN];
  175 
  176                 if (count_perc != 0) {
  177                         /* High resolution algorithm */
  178                         temp &= ~0x0001;
  179                         val = temp * 500000 - 250000 +
  180                             ((count_perc - count_remain) * 1000000) /
  181                             count_perc;
  182                 } else {
  183                         val = temp * 500000;
  184                 }
  185                 sc->sc_sensor.value = 273150000 + val;
  186         }
  187 
  188 done:
  189         onewire_unlock(sc->sc_onewire);
  190         rw_exit_write(&sc->sc_lock);
  191 }

/* [<][>][^][v][top][bottom][index][help] */