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/adm1030.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  * Copyright (c) 2011 Justin Hibbits
    3  * Copyright (c) 2010 Andreas Tobler
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #include <sys/param.h>
   32 #include <sys/bus.h>
   33 #include <sys/systm.h>
   34 #include <sys/module.h>
   35 #include <sys/callout.h>
   36 #include <sys/conf.h>
   37 #include <sys/cpu.h>
   38 #include <sys/ctype.h>
   39 #include <sys/kernel.h>
   40 #include <sys/kthread.h>
   41 #include <sys/limits.h>
   42 #include <sys/reboot.h>
   43 #include <sys/rman.h>
   44 #include <sys/sysctl.h>
   45 #include <sys/unistd.h>
   46 
   47 #include <machine/bus.h>
   48 #include <machine/md_var.h>
   49 
   50 #include <dev/iicbus/iicbus.h>
   51 #include <dev/iicbus/iiconf.h>
   52 
   53 #include <dev/ofw/openfirm.h>
   54 #include <dev/ofw/ofw_bus.h>
   55 #include <powerpc/powermac/powermac_thermal.h>
   56 
   57 struct adm1030_softc {
   58         struct pmac_fan fan;
   59         device_t        sc_dev;
   60         struct intr_config_hook enum_hook;
   61         uint32_t        sc_addr;
   62         int             sc_pwm;
   63 };
   64 
   65 /* Regular bus attachment functions */
   66 static int      adm1030_probe(device_t);
   67 static int      adm1030_attach(device_t);
   68 
   69 /* Utility functions */
   70 static void     adm1030_start(void *xdev);
   71 static int      adm1030_write_byte(device_t dev, uint32_t addr, uint8_t reg, uint8_t buf);
   72 static int      adm1030_set(struct adm1030_softc *fan, int pwm);
   73 static int      adm1030_sysctl(SYSCTL_HANDLER_ARGS);
   74 
   75 static device_method_t adm1030_methods[] = {
   76         /* Device interface */
   77         DEVMETHOD(device_probe, adm1030_probe),
   78         DEVMETHOD(device_attach, adm1030_attach),
   79         {0, 0},
   80 };
   81 
   82 static driver_t adm1030_driver = {
   83         "adm1030",
   84         adm1030_methods,
   85         sizeof(struct adm1030_softc)
   86 };
   87 
   88 DRIVER_MODULE(adm1030, iicbus, adm1030_driver, 0, 0);
   89 
   90 static int
   91 adm1030_write_byte(device_t dev, uint32_t addr, uint8_t reg, uint8_t byte)
   92 {
   93         unsigned char   buf[4];
   94         int try = 0;
   95 
   96         struct iic_msg  msg[] = {
   97                 {addr, IIC_M_WR, 0, buf}
   98         };
   99 
  100         msg[0].len = 2;
  101         buf[0] = reg;
  102         buf[1] = byte;
  103 
  104         for (;;)
  105         {
  106                 if (iicbus_transfer(dev, msg, 1) == 0)
  107                         return (0);
  108 
  109                 if (++try > 5) {
  110                         device_printf(dev, "iicbus write failed\n");
  111                         return (-1);
  112                 }
  113                 pause("adm1030_write_byte", hz);
  114         }
  115 }
  116 
  117 static int
  118 adm1030_probe(device_t dev)
  119 {
  120         const char     *name, *compatible;
  121         struct adm1030_softc *sc;
  122         phandle_t       handle;
  123         phandle_t       thermostat;
  124 
  125         name = ofw_bus_get_name(dev);
  126         compatible = ofw_bus_get_compat(dev);
  127         handle = ofw_bus_get_node(dev);
  128 
  129         if (!name)
  130                 return (ENXIO);
  131 
  132         if (strcmp(name, "fan") != 0 || strcmp(compatible, "adm1030") != 0)
  133                 return (ENXIO);
  134 
  135         /* This driver can only be used if there's an associated temp sensor. */
  136         if (OF_getprop(handle, "platform-getTemp", &thermostat, sizeof(thermostat)) < 0)
  137                 return (ENXIO);
  138 
  139         sc = device_get_softc(dev);
  140         sc->sc_dev = dev;
  141         sc->sc_addr = iicbus_get_addr(dev);
  142 
  143         device_set_desc(dev, "G4 MDD Fan driver");
  144 
  145         return (0);
  146 }
  147 
  148 static int
  149 adm1030_attach(device_t dev)
  150 {
  151         struct adm1030_softc *sc;
  152         struct sysctl_ctx_list *ctx;
  153         struct sysctl_oid *tree;
  154 
  155         sc = device_get_softc(dev);
  156 
  157         sc->enum_hook.ich_func = adm1030_start;
  158         sc->enum_hook.ich_arg = dev;
  159 
  160         /*
  161          * Wait until interrupts are available, which won't be until the openpic is
  162          * intialized.
  163          */
  164 
  165         if (config_intrhook_establish(&sc->enum_hook) != 0)
  166                 return (ENOMEM);
  167 
  168         ctx = device_get_sysctl_ctx(dev);
  169         tree = device_get_sysctl_tree(dev);
  170         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "pwm",
  171                         CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev,
  172                         0, adm1030_sysctl, "I", "Fan PWM Rate");
  173 
  174         return (0);
  175 }
  176 
  177 static void
  178 adm1030_start(void *xdev)
  179 {
  180         struct adm1030_softc *sc;
  181 
  182         device_t        dev = (device_t) xdev;
  183 
  184         sc = device_get_softc(dev);
  185 
  186         /* Start the adm1030 device. */
  187         adm1030_write_byte(sc->sc_dev, sc->sc_addr, 0x1, 0x1);
  188         adm1030_write_byte(sc->sc_dev, sc->sc_addr, 0x0, 0x95);
  189         adm1030_write_byte(sc->sc_dev, sc->sc_addr, 0x23, 0x91);
  190 
  191         /* Use the RPM fields as PWM duty cycles. */
  192         sc->fan.min_rpm = 0;
  193         sc->fan.max_rpm = 0x0F;
  194         sc->fan.default_rpm = 2;
  195 
  196         strcpy(sc->fan.name, "MDD Case fan");
  197         sc->fan.zone = 0;
  198         sc->fan.read = NULL;
  199         sc->fan.set = (int (*)(struct pmac_fan *, int))adm1030_set;
  200         config_intrhook_disestablish(&sc->enum_hook);
  201 
  202         pmac_thermal_fan_register(&sc->fan);
  203 }
  204 
  205 static int adm1030_set(struct adm1030_softc *fan, int pwm)
  206 {
  207         /* Clamp the PWM to 0-0xF, one nibble. */
  208         if (pwm > 0xF)
  209                 pwm = 0xF;
  210         if (pwm < 0)
  211                 pwm = 0;
  212 
  213         if (adm1030_write_byte(fan->sc_dev, fan->sc_addr, 0x22, pwm) < 0)
  214                 return (-1);
  215 
  216         fan->sc_pwm = pwm;
  217         return (0);
  218 }
  219 
  220 static int
  221 adm1030_sysctl(SYSCTL_HANDLER_ARGS)
  222 {
  223         device_t adm1030;
  224         struct adm1030_softc *sc;
  225         int pwm, error;
  226 
  227         adm1030 = arg1;
  228         sc = device_get_softc(adm1030);
  229 
  230         pwm = sc->sc_pwm;
  231 
  232         error = sysctl_handle_int(oidp, &pwm, 0, req);
  233 
  234         if (error || !req->newptr)
  235                 return (error);
  236 
  237         return (adm1030_set(sc, pwm));
  238 }

Cache object: 041a07de8d575cf3d2467ecb841c3fcd


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