The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/iicbus/tmp461.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2021 Alstom Group.
    5  * Copyright (c) 2021 Semihalf.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #include "opt_platform.h"
   32 
   33 #include <sys/param.h>
   34 #include <sys/bus.h>
   35 #include <sys/lock.h>
   36 #include <sys/mutex.h>
   37 #include <sys/module.h>
   38 #include <sys/ctype.h>
   39 #include <sys/kernel.h>
   40 #include <sys/libkern.h>
   41 #include <sys/sysctl.h>
   42 
   43 #include <dev/iicbus/iicbus.h>
   44 #include <dev/iicbus/iiconf.h>
   45 
   46 #include <dev/ofw/ofw_bus_subr.h>
   47 #include <dev/ofw/ofw_bus.h>
   48 
   49 #define BIT(x)                                  (1UL << (x))
   50 
   51 /* register map */
   52 #define TMP461_LOCAL_TEMP_REG_MSB               0x0
   53 #define TMP461_LOCAL_TEMP_REG_LSB               0x15
   54 #define TMP461_GLOBAL_TEMP_REG_MSB              0x1
   55 #define TMP461_GLOBAL_TEMP_REG_LSB              0x10
   56 #define TMP461_STATUS_REG                       0x2
   57 #define TMP461_STATUS_REG_TEMP_LOCAL            BIT(2)
   58 #define TMP461_CONFIG_REG_R                     0x3
   59 #define TMP461_CONFIG_REG_W                     0x9
   60 #define TMP461_CONFIG_REG_TEMP_RANGE_BIT        BIT(2)
   61 #define TMP461_CONFIG_REG_STANDBY_BIT           BIT(6)
   62 #define TMP461_CONVERSION_RATE_REG              0x4
   63 #define TMP461_ONESHOT_REG                      0xF
   64 #define TMP461_EXTENDED_TEMP_MODIFIER           64
   65 
   66 /* 28.4 fixed point representation of 273.15f */
   67 #define TMP461_C_TO_K_FIX                       4370
   68 
   69 #define TMP461_SENSOR_MAX_CONV_TIME             16000000
   70 #define TMP461_LOCAL_MEASURE                    0
   71 #define TMP461_REMOTE_MEASURE                   1
   72 
   73 /* flags */
   74 #define TMP461_LOCAL_TEMP_DOUBLE_REG            BIT(0)
   75 #define TMP461_REMOTE_TEMP_DOUBLE_REG           BIT(1)
   76 
   77 static int tmp461_probe(device_t dev);
   78 static int tmp461_attach(device_t dev);
   79 static int tmp461_read_1(device_t dev, uint8_t reg, uint8_t *data);
   80 static int tmp461_write_1(device_t dev, uint8_t reg, uint8_t data);
   81 static int tmp461_read_temperature(device_t dev, int32_t *temperature, bool mode);
   82 static int tmp461_detach(device_t dev);
   83 static int tmp461_sensor_sysctl(SYSCTL_HANDLER_ARGS);
   84 
   85 static device_method_t tmp461_methods[] = {
   86         DEVMETHOD(device_probe,         tmp461_probe),
   87         DEVMETHOD(device_attach,        tmp461_attach),
   88         DEVMETHOD(device_detach,        tmp461_detach),
   89 
   90         DEVMETHOD_END
   91 };
   92 
   93 struct tmp461_softc {
   94         struct mtx              mtx;
   95         uint8_t                 conf;
   96 };
   97 
   98 static driver_t tmp461_driver = {
   99         "tmp461_dev",
  100         tmp461_methods,
  101         sizeof(struct tmp461_softc)
  102 };
  103 
  104 struct tmp461_data {
  105         const char      *compat;
  106         const char      *desc;
  107         uint8_t         flags;
  108 };
  109 
  110 static struct tmp461_data sensor_list[] = {
  111         {"adt7461", "ADT7461 Thernal Sensor Information",
  112             TMP461_REMOTE_TEMP_DOUBLE_REG},
  113         {"tmp461", "TMP461 Thernal Sensor Information",
  114             TMP461_LOCAL_TEMP_DOUBLE_REG | TMP461_REMOTE_TEMP_DOUBLE_REG}
  115 };
  116 
  117 static struct ofw_compat_data tmp461_compat_data[] = {
  118         {"adi,adt7461",         (uintptr_t)&sensor_list[0]},
  119         {"ti,tmp461",           (uintptr_t)&sensor_list[1]},
  120         {NULL,                  0}
  121 };
  122 
  123 DRIVER_MODULE(tmp461, iicbus, tmp461_driver, 0, 0);
  124 IICBUS_FDT_PNP_INFO(tmp461_compat_data);
  125 
  126 static int
  127 tmp461_attach(device_t dev)
  128 {
  129         struct sysctl_oid *sensor_root_oid;
  130         struct tmp461_data *compat_data;
  131         struct sysctl_ctx_list *ctx;
  132         struct tmp461_softc *sc;
  133         uint8_t data;
  134 
  135         sc = device_get_softc(dev);
  136         compat_data = (struct tmp461_data *)
  137             ofw_bus_search_compatible(dev, tmp461_compat_data)->ocd_data;
  138         sc->conf = compat_data->flags;
  139         ctx = device_get_sysctl_ctx(dev);
  140 
  141         mtx_init(&sc->mtx, "tmp461 temperature", "temperature", MTX_DEF);
  142 
  143         sensor_root_oid = SYSCTL_ADD_NODE(ctx, SYSCTL_STATIC_CHILDREN(_hw),
  144             OID_AUTO, "temperature", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
  145             "Thermal Sensor Information");
  146         if (sensor_root_oid == NULL)
  147                 return (ENXIO);
  148 
  149         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sensor_root_oid), OID_AUTO,
  150             "local_sensor", CTLTYPE_INT | CTLFLAG_RD, dev,
  151             TMP461_LOCAL_MEASURE, tmp461_sensor_sysctl,
  152             "IK1", compat_data->desc);
  153 
  154         /* get status register */
  155         if (tmp461_read_1(dev, TMP461_STATUS_REG, &data) != 0)
  156                 return (ENXIO);
  157 
  158         if (!(data & TMP461_STATUS_REG_TEMP_LOCAL))
  159                 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sensor_root_oid), OID_AUTO,
  160                     "remote_sensor", CTLTYPE_INT | CTLFLAG_RD, dev,
  161                     TMP461_REMOTE_MEASURE, tmp461_sensor_sysctl,
  162                     "IK1", compat_data->desc);
  163 
  164         /* set standby mode */
  165         if (tmp461_read_1(dev, TMP461_CONFIG_REG_R, &data) != 0)
  166                 return (ENXIO);
  167 
  168         data |= TMP461_CONFIG_REG_STANDBY_BIT;
  169         if (tmp461_write_1(dev, TMP461_CONFIG_REG_W, data) != 0)
  170                 return (ENXIO);
  171 
  172         return (0);
  173 }
  174 
  175 static int
  176 tmp461_probe(device_t dev)
  177 {
  178         struct tmp461_data *compat_data;
  179 
  180         if (!ofw_bus_status_okay(dev))
  181                 return (ENXIO);
  182 
  183         compat_data = (struct tmp461_data *)
  184             ofw_bus_search_compatible(dev, tmp461_compat_data)->ocd_data;
  185         if (!compat_data)
  186                 return (ENXIO);
  187 
  188         device_set_desc(dev, compat_data->compat);
  189 
  190         return (BUS_PROBE_GENERIC);
  191 }
  192 
  193 static int
  194 tmp461_detach(device_t dev)
  195 {
  196         struct tmp461_softc *sc;
  197 
  198         sc = device_get_softc(dev);
  199         mtx_destroy(&sc->mtx);
  200 
  201         return (0);
  202 }
  203 
  204 static int
  205 tmp461_read_1(device_t dev, uint8_t reg, uint8_t *data)
  206 {
  207         int error;
  208 
  209         error = iicdev_readfrom(dev, reg, (void *) data, 1, IIC_DONTWAIT);
  210         if (error != 0)
  211                 device_printf(dev, "Failed to read from device\n");
  212 
  213         return (error);
  214 }
  215 
  216 static int
  217 tmp461_write_1(device_t dev, uint8_t reg, uint8_t data)
  218 {
  219         int error;
  220 
  221         error = iicdev_writeto(dev, reg, (void *) &data, 1, IIC_DONTWAIT);
  222         if (error != 0)
  223                 device_printf(dev, "Failed to write to device\n");
  224 
  225         return (error);
  226 }
  227 
  228 static int
  229 tmp461_read_temperature(device_t dev, int32_t *temperature, bool remote_measure)
  230 {
  231         uint8_t data, offset, reg;
  232         struct tmp461_softc *sc;
  233         int error;
  234 
  235         sc = device_get_softc(dev);
  236 
  237         mtx_lock(&sc->mtx);
  238 
  239         error = tmp461_read_1(dev, TMP461_CONVERSION_RATE_REG, &data);
  240         if (error != 0)
  241                 goto fail;
  242 
  243         /* trigger sample*/
  244         error = tmp461_write_1(dev, TMP461_ONESHOT_REG, 0xFF);
  245         if (error != 0)
  246                 goto fail;
  247 
  248         /* wait for conversion time */
  249         DELAY(TMP461_SENSOR_MAX_CONV_TIME/(1UL<<data));
  250 
  251         /* read config register offset */
  252         error = tmp461_read_1(dev, TMP461_CONFIG_REG_R, &data);
  253         if (error != 0)
  254                 goto fail;
  255 
  256         offset = (data & TMP461_CONFIG_REG_TEMP_RANGE_BIT ?
  257             TMP461_EXTENDED_TEMP_MODIFIER : 0);
  258 
  259         reg = remote_measure ?
  260             TMP461_GLOBAL_TEMP_REG_MSB : TMP461_LOCAL_TEMP_REG_MSB;
  261 
  262         /* read temeperature value*/
  263         error = tmp461_read_1(dev, reg, &data);
  264         if (error != 0)
  265                 goto fail;
  266 
  267         data -= offset;
  268         *temperature = signed_extend32(data, 0, 8) << 4;
  269 
  270         if (remote_measure) {
  271                 if (sc->conf & TMP461_REMOTE_TEMP_DOUBLE_REG) {
  272                         error = tmp461_read_1(dev,
  273                             TMP461_GLOBAL_TEMP_REG_LSB, &data);
  274                         if (error != 0)
  275                                 goto fail;
  276 
  277                         *temperature |= data >> 4;
  278                 }
  279         } else {
  280                 if (sc->conf & TMP461_LOCAL_TEMP_DOUBLE_REG) {
  281                         error = tmp461_read_1(dev,
  282                             TMP461_LOCAL_TEMP_REG_LSB, &data);
  283                         if (error != 0)
  284                                 goto fail;
  285 
  286                         *temperature |= data >> 4;
  287                 }
  288         }
  289         *temperature = (((*temperature + TMP461_C_TO_K_FIX) * 10) >> 4);
  290 
  291 fail:
  292         mtx_unlock(&sc->mtx);
  293         return (error);
  294 }
  295 
  296 static int
  297 tmp461_sensor_sysctl(SYSCTL_HANDLER_ARGS)
  298 {
  299         int32_t temperature;
  300         device_t dev;
  301         int error;
  302         bool mode;
  303 
  304         dev = arg1;
  305         mode = arg2;
  306 
  307         error = tmp461_read_temperature(dev, &temperature, mode);
  308         if (error != 0)
  309                 return (error);
  310 
  311         return (sysctl_handle_int(oidp, &temperature, 0, req));
  312 }

Cache object: ab654210812e5f32a5668656a85b2d80


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.