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/powerpc/powermac/smusat.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) 2010 Nathan Whitehorn
    5  * All rights reserved.
    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,
   21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/module.h>
   36 #include <sys/bus.h>
   37 #include <sys/conf.h>
   38 #include <sys/cpu.h>
   39 #include <sys/ctype.h>
   40 #include <sys/kernel.h>
   41 #include <sys/sysctl.h>
   42 
   43 #include <dev/iicbus/iicbus.h>
   44 #include <dev/iicbus/iiconf.h>
   45 #include <dev/ofw/ofw_bus.h>
   46 #include <dev/ofw/openfirm.h>
   47 
   48 #include <powerpc/powermac/powermac_thermal.h>
   49 
   50 struct smu_sensor {
   51         struct pmac_therm therm;
   52         device_t dev;
   53 
   54         cell_t  reg;
   55         enum {
   56                 SMU_CURRENT_SENSOR,
   57                 SMU_VOLTAGE_SENSOR,
   58                 SMU_POWER_SENSOR,
   59                 SMU_TEMP_SENSOR
   60         } type;
   61 };
   62 
   63 static int      smusat_probe(device_t);
   64 static int      smusat_attach(device_t);
   65 static int      smusat_sensor_sysctl(SYSCTL_HANDLER_ARGS);
   66 static int      smusat_sensor_read(struct smu_sensor *sens);
   67 
   68 static MALLOC_DEFINE(M_SMUSAT, "smusat", "SMU Sattelite Sensors");
   69 
   70 static device_method_t  smusat_methods[] = {
   71         /* Device interface */
   72         DEVMETHOD(device_probe,         smusat_probe),
   73         DEVMETHOD(device_attach,        smusat_attach),
   74         { 0, 0 },
   75 };
   76 
   77 struct smusat_softc {
   78         struct smu_sensor *sc_sensors;
   79         int     sc_nsensors;
   80 
   81         uint8_t sc_cache[16];
   82         time_t  sc_last_update;
   83 };
   84 
   85 static driver_t smusat_driver = {
   86         "smusat",
   87         smusat_methods,
   88         sizeof(struct smusat_softc)
   89 };
   90 
   91 DRIVER_MODULE(smusat, iicbus, smusat_driver, 0, 0);
   92 
   93 static int
   94 smusat_probe(device_t dev)
   95 {
   96         const char *compat = ofw_bus_get_compat(dev);
   97 
   98         if (compat == NULL || strcmp(compat, "smu-sat") != 0)
   99                 return (ENXIO);
  100 
  101         device_set_desc(dev, "SMU Satellite Sensors");
  102         return (0);
  103 }
  104 
  105 static int
  106 smusat_attach(device_t dev)
  107 {
  108         phandle_t child;
  109         struct smu_sensor *sens;
  110         struct smusat_softc *sc;
  111         struct sysctl_oid *sensroot_oid;
  112         struct sysctl_ctx_list *ctx;
  113         char type[32];
  114         int i;
  115 
  116         sc = device_get_softc(dev);
  117         sc->sc_nsensors = 0;
  118         sc->sc_last_update = 0;
  119 
  120         for (child = OF_child(ofw_bus_get_node(dev)); child != 0;
  121             child = OF_peer(child))
  122                 sc->sc_nsensors++;
  123 
  124         if (sc->sc_nsensors == 0) {
  125                 device_printf(dev, "WARNING: No sensors detected!\n");
  126                 return (-1);
  127         }
  128             
  129         sc->sc_sensors = malloc(sc->sc_nsensors * sizeof(struct smu_sensor),
  130             M_SMUSAT, M_WAITOK | M_ZERO);
  131 
  132         sens = sc->sc_sensors;
  133         sc->sc_nsensors = 0;
  134 
  135         ctx = device_get_sysctl_ctx(dev);
  136         sensroot_oid = device_get_sysctl_tree(dev);
  137 
  138         for (child = OF_child(ofw_bus_get_node(dev)); child != 0;
  139             child = OF_peer(child)) {
  140                 char sysctl_name[40], sysctl_desc[40];
  141                 const char *units;
  142 
  143                 sens->dev = dev;
  144                 sens->reg = 0;
  145                 OF_getprop(child, "reg", &sens->reg, sizeof(sens->reg));
  146                 if (sens->reg < 0x30)
  147                         continue;
  148                 sens->reg -= 0x30;
  149 
  150                 OF_getprop(child, "zone", &sens->therm.zone, sizeof(int));
  151                 OF_getprop(child, "location", sens->therm.name,
  152                     sizeof(sens->therm.name));
  153 
  154                 OF_getprop(child, "device_type", type, sizeof(type));
  155 
  156                 if (strcmp(type, "current-sensor") == 0) {
  157                         sens->type = SMU_CURRENT_SENSOR;
  158                         units = "mA";
  159                 } else if (strcmp(type, "temp-sensor") == 0) {
  160                         sens->type = SMU_TEMP_SENSOR;
  161                         units = "C";
  162                 } else if (strcmp(type, "voltage-sensor") == 0) {
  163                         sens->type = SMU_VOLTAGE_SENSOR;
  164                         units = "mV";
  165                 } else if (strcmp(type, "power-sensor") == 0) {
  166                         sens->type = SMU_POWER_SENSOR;
  167                         units = "mW";
  168                 } else {
  169                         continue;
  170                 }
  171 
  172                 for (i = 0; i < strlen(sens->therm.name); i++) {
  173                         sysctl_name[i] = tolower(sens->therm.name[i]);
  174                         if (isspace(sysctl_name[i]))
  175                                 sysctl_name[i] = '_';
  176                 }
  177                 sysctl_name[i] = 0;
  178 
  179                 sprintf(sysctl_desc,"%s (%s)", sens->therm.name, units);
  180                 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sensroot_oid), OID_AUTO,
  181                     sysctl_name, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev,
  182                     sc->sc_nsensors, smusat_sensor_sysctl,
  183                     (sens->type == SMU_TEMP_SENSOR) ? "IK" : "I", sysctl_desc);
  184 
  185                 if (sens->type == SMU_TEMP_SENSOR) {
  186                         /* Make up some numbers */
  187                         sens->therm.target_temp = 500 + 2731; /* 50 C */
  188                         sens->therm.max_temp = 900 + 2731; /* 90 C */
  189                         sens->therm.read =
  190                             (int (*)(struct pmac_therm *))smusat_sensor_read;
  191                         pmac_thermal_sensor_register(&sens->therm);
  192                 }
  193 
  194                 sens++;
  195                 sc->sc_nsensors++;
  196         }
  197 
  198         return (0);
  199 }
  200 
  201 static int
  202 smusat_updatecache(device_t dev)
  203 {
  204         uint8_t reg = 0x3f;
  205         uint8_t value[16];
  206         struct smusat_softc *sc = device_get_softc(dev);
  207         int error;
  208         struct iic_msg msgs[2] = {
  209             {0, IIC_M_WR | IIC_M_NOSTOP, 1, &reg},
  210             {0, IIC_M_RD, 16, value},
  211         };
  212 
  213         msgs[0].slave = msgs[1].slave = iicbus_get_addr(dev);
  214         error = iicbus_transfer(dev, msgs, 2);
  215         if (error)
  216                 return (error);
  217 
  218         sc->sc_last_update = time_uptime;
  219         memcpy(sc->sc_cache, value, sizeof(value));
  220         return (0);
  221 }
  222 
  223 static int
  224 smusat_sensor_read(struct smu_sensor *sens)
  225 {
  226         int value, error;
  227         device_t dev;
  228         struct smusat_softc *sc;
  229 
  230         dev = sens->dev;
  231         sc = device_get_softc(dev);
  232         error = 0;
  233 
  234         if (time_uptime - sc->sc_last_update > 1)
  235                 error = smusat_updatecache(dev);
  236         if (error)
  237                 return (-error);
  238 
  239         value = (sc->sc_cache[sens->reg*2] << 8) +
  240             sc->sc_cache[sens->reg*2 + 1];
  241         if (value == 0xffff) {
  242                 sc->sc_last_update = 0; /* Result was bad, don't cache */
  243                 return (-EINVAL);
  244         }
  245 
  246         switch (sens->type) {
  247         case SMU_TEMP_SENSOR:
  248                 /* 16.16 */
  249                 value <<= 10;
  250                 /* From 16.16 to 0.1 C */
  251                 value = 10*(value >> 16) + ((10*(value & 0xffff)) >> 16) + 2731;
  252                 break;
  253         case SMU_VOLTAGE_SENSOR:
  254                 /* 16.16 */
  255                 value <<= 4;
  256                 /* Kill the .16 */
  257                 value >>= 16;
  258                 break;
  259         case SMU_CURRENT_SENSOR:
  260                 /* 16.16 */
  261                 value <<= 8;
  262                 /* Kill the .16 */
  263                 value >>= 16;
  264                 break;
  265         case SMU_POWER_SENSOR:
  266                 /* Doesn't exist */
  267                 break;
  268         }
  269 
  270         return (value);
  271 }
  272 
  273 static int
  274 smusat_sensor_sysctl(SYSCTL_HANDLER_ARGS)
  275 {
  276         device_t dev;
  277         struct smusat_softc *sc;
  278         struct smu_sensor *sens;
  279         int value, error;
  280 
  281         dev = arg1;
  282         sc = device_get_softc(dev);
  283         sens = &sc->sc_sensors[arg2];
  284 
  285         value = smusat_sensor_read(sens);
  286         if (value < 0)
  287                 return (EBUSY);
  288 
  289         error = sysctl_handle_int(oidp, &value, 0, req);
  290 
  291         return (error);
  292 }

Cache object: 543b408ba0ba6a3cb058b250a2ac58e3


[ 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.