Home | History | Annotate | Line # | Download | only in i2c
dbcool.c revision 1.15
      1  1.15    dyoung /*	$NetBSD: dbcool.c,v 1.15 2010/02/24 22:37:57 dyoung Exp $ */
      2   1.1  pgoyette 
      3   1.1  pgoyette /*-
      4   1.1  pgoyette  * Copyright (c) 2008 The NetBSD Foundation, Inc.
      5   1.1  pgoyette  * All rights reserved.
      6   1.1  pgoyette  *
      7   1.1  pgoyette  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1  pgoyette  * by Paul Goyette
      9   1.1  pgoyette  *
     10   1.1  pgoyette  * Redistribution and use in source and binary forms, with or without
     11   1.1  pgoyette  * modification, are permitted provided that the following conditions
     12   1.1  pgoyette  * are met:
     13   1.1  pgoyette  * 1. Redistributions of source code must retain the above copyright
     14   1.1  pgoyette  *    notice, this list of conditions and the following disclaimer.
     15   1.1  pgoyette  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1  pgoyette  *    notice, this list of conditions and the following disclaimer in the
     17   1.1  pgoyette  *    documentation and/or other materials provided with the distribution.
     18   1.1  pgoyette  *
     19   1.1  pgoyette  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1  pgoyette  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1  pgoyette  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.1  pgoyette  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1  pgoyette  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1  pgoyette  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1  pgoyette  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1  pgoyette  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1  pgoyette  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1  pgoyette  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1  pgoyette  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1  pgoyette  */
     31   1.1  pgoyette 
     32   1.1  pgoyette /*
     33   1.1  pgoyette  * a driver for the dbCool(tm) family of environmental controllers
     34   1.1  pgoyette  *
     35   1.1  pgoyette  * Data sheets for the various supported chips are available at
     36   1.1  pgoyette  *
     37   1.1  pgoyette  *	http://www.onsemi.com/pub/Collateral/ADM1027-D.PDF
     38   1.1  pgoyette  *	http://www.onsemi.com/pub/Collateral/ADM1030-D.PDF
     39   1.1  pgoyette  *	http://www.onsemi.com/pub/Collateral/ADT7463-D.PDF
     40   1.1  pgoyette  *	http://www.onsemi.com/pub/Collateral/ADT7466.PDF
     41   1.1  pgoyette  *	http://www.onsemi.com/pub/Collateral/ADT7467-D.PDF
     42   1.1  pgoyette  *	http://www.onsemi.com/pub/Collateral/ADT7468-D.PDF
     43   1.1  pgoyette  *	http://www.onsemi.com/pub/Collateral/ADT7473-D.PDF
     44   1.1  pgoyette  *	http://www.onsemi.com/pub/Collateral/ADT7475-D.PDF
     45   1.1  pgoyette  *	http://www.onsemi.com/pub/Collateral/ADT7476-D.PDF
     46   1.2  pgoyette  *	http://www.onsemi.com/pub/Collateral/ADT7490-D.PDF
     47   1.1  pgoyette  *
     48   1.2  pgoyette  * (URLs are correct as of October 5, 2008)
     49   1.1  pgoyette  */
     50   1.1  pgoyette 
     51   1.1  pgoyette #include <sys/cdefs.h>
     52  1.15    dyoung __KERNEL_RCSID(0, "$NetBSD: dbcool.c,v 1.15 2010/02/24 22:37:57 dyoung Exp $");
     53   1.1  pgoyette 
     54   1.1  pgoyette #include <sys/param.h>
     55   1.1  pgoyette #include <sys/systm.h>
     56   1.1  pgoyette #include <sys/kernel.h>
     57   1.1  pgoyette #include <sys/device.h>
     58   1.1  pgoyette #include <sys/malloc.h>
     59   1.1  pgoyette #include <sys/sysctl.h>
     60   1.1  pgoyette 
     61   1.1  pgoyette #include <uvm/uvm_extern.h>
     62   1.1  pgoyette 
     63   1.1  pgoyette #include <dev/i2c/dbcool_var.h>
     64   1.1  pgoyette #include <dev/i2c/dbcool_reg.h>
     65   1.1  pgoyette 
     66   1.1  pgoyette /* Config interface */
     67   1.1  pgoyette static int dbcool_match(device_t, cfdata_t, void *);
     68   1.1  pgoyette static void dbcool_attach(device_t, device_t, void *);
     69   1.1  pgoyette static int dbcool_detach(device_t, int);
     70   1.1  pgoyette 
     71   1.1  pgoyette /* Device attributes */
     72   1.1  pgoyette static int dbcool_supply_voltage(struct dbcool_softc *);
     73   1.2  pgoyette static bool dbcool_islocked(struct dbcool_softc *);
     74   1.1  pgoyette 
     75   1.1  pgoyette /* Sensor read functions */
     76   1.1  pgoyette static void dbcool_refresh(struct sysmon_envsys *, envsys_data_t *);
     77   1.1  pgoyette static int dbcool_read_rpm(struct dbcool_softc *, uint8_t);
     78   1.1  pgoyette static int dbcool_read_temp(struct dbcool_softc *, uint8_t, bool);
     79   1.2  pgoyette static int dbcool_read_volt(struct dbcool_softc *, uint8_t, int, bool);
     80   1.1  pgoyette 
     81   1.1  pgoyette /* SYSCTL Helpers */
     82   1.2  pgoyette static int sysctl_dbcool_temp(SYSCTLFN_PROTO);
     83   1.2  pgoyette static int sysctl_adm1030_temp(SYSCTLFN_PROTO);
     84   1.1  pgoyette static int sysctl_adm1030_trange(SYSCTLFN_PROTO);
     85   1.1  pgoyette static int sysctl_dbcool_duty(SYSCTLFN_PROTO);
     86   1.1  pgoyette static int sysctl_dbcool_behavior(SYSCTLFN_PROTO);
     87   1.2  pgoyette static int sysctl_dbcool_slope(SYSCTLFN_PROTO);
     88   1.1  pgoyette static int sysctl_dbcool_volt_limit(SYSCTLFN_PROTO);
     89   1.1  pgoyette static int sysctl_dbcool_temp_limit(SYSCTLFN_PROTO);
     90   1.1  pgoyette static int sysctl_dbcool_fan_limit(SYSCTLFN_PROTO);
     91   1.1  pgoyette static int sysctl_dbcool_thyst(SYSCTLFN_PROTO);
     92   1.1  pgoyette static int sysctl_dbcool_vid(SYSCTLFN_PROTO);
     93   1.1  pgoyette 
     94   1.2  pgoyette /* Set-up subroutines */
     95   1.2  pgoyette static void dbcool_setup_controllers(struct dbcool_softc *,
     96   1.2  pgoyette 	const struct sysctlnode *, int, int);
     97   1.2  pgoyette static int dbcool_setup_sensors(struct dbcool_softc *,
     98   1.2  pgoyette 	const struct sysctlnode *, int, int);
     99   1.2  pgoyette static int dbcool_attach_sensor(struct dbcool_softc *,
    100   1.2  pgoyette 	const struct sysctlnode *, int, int (*)(SYSCTLFN_PROTO));
    101   1.2  pgoyette 
    102   1.1  pgoyette #ifdef DBCOOL_DEBUG
    103   1.1  pgoyette static int sysctl_dbcool_reg_select(SYSCTLFN_PROTO);
    104   1.1  pgoyette static int sysctl_dbcool_reg_access(SYSCTLFN_PROTO);
    105   1.1  pgoyette #endif /* DBCOOL_DEBUG */
    106   1.1  pgoyette 
    107   1.1  pgoyette /*
    108   1.1  pgoyette  * Descriptions for SYSCTL entries
    109   1.1  pgoyette  */
    110   1.2  pgoyette struct dbc_sysctl_info {
    111   1.1  pgoyette 	const char *name;
    112   1.1  pgoyette 	const char *desc;
    113   1.2  pgoyette 	bool lockable;
    114   1.1  pgoyette 	int (*helper)(SYSCTLFN_PROTO);
    115   1.1  pgoyette };
    116   1.1  pgoyette 
    117   1.2  pgoyette static struct dbc_sysctl_info dbc_sysctl_table[] = {
    118   1.2  pgoyette 	/*
    119   1.2  pgoyette 	 * The first several entries must remain in the same order as the
    120   1.2  pgoyette 	 * corresponding entries in enum dbc_pwm_params
    121   1.2  pgoyette 	 */
    122   1.1  pgoyette 	{ "behavior",		"operating behavior and temp selector",
    123   1.2  pgoyette 		true, sysctl_dbcool_behavior },
    124   1.1  pgoyette 	{ "min_duty",		"minimum fan controller PWM duty cycle",
    125   1.2  pgoyette 		true, sysctl_dbcool_duty },
    126   1.1  pgoyette 	{ "max_duty",		"maximum fan controller PWM duty cycle",
    127   1.2  pgoyette 		true, sysctl_dbcool_duty },
    128   1.1  pgoyette 	{ "cur_duty",		"current fan controller PWM duty cycle",
    129   1.2  pgoyette 		false, sysctl_dbcool_duty },
    130   1.2  pgoyette 
    131   1.2  pgoyette 	/*
    132   1.2  pgoyette 	 * The rest of these should be in the order in which they
    133   1.2  pgoyette 	 * are to be stored in the sysctl tree;  the table index is
    134   1.2  pgoyette 	 * used as the high-order bits of the sysctl_num to maintain
    135   1.2  pgoyette 	 * the sequence.
    136   1.2  pgoyette 	 *
    137   1.2  pgoyette 	 * If you rearrange the order of these items, be sure to
    138   1.2  pgoyette 	 * update the sysctl_index in the XXX_sensor_table[] for
    139   1.2  pgoyette 	 * the various chips!
    140   1.2  pgoyette 	 */
    141   1.2  pgoyette 	{ "Trange",		"temp slope/range to reach 100% duty cycle",
    142   1.2  pgoyette 		true, sysctl_dbcool_slope },
    143   1.1  pgoyette 	{ "Tmin",		"temp at which to start fan controller",
    144   1.2  pgoyette 		true, sysctl_dbcool_temp },
    145   1.1  pgoyette 	{ "Ttherm",		"temp at which THERM is asserted",
    146   1.2  pgoyette 		true, sysctl_dbcool_temp },
    147   1.1  pgoyette 	{ "Thyst",		"temp hysteresis for stopping fan controller",
    148   1.2  pgoyette 		true, sysctl_dbcool_thyst },
    149   1.1  pgoyette 	{ "Tmin",		"temp at which to start fan controller",
    150   1.2  pgoyette 		true, sysctl_adm1030_temp },
    151   1.2  pgoyette 	{ "Trange",		"temp slope/range to reach 100% duty cycle",
    152   1.2  pgoyette 		true, sysctl_adm1030_trange },
    153   1.1  pgoyette };
    154   1.1  pgoyette 
    155   1.1  pgoyette static const char *dbc_sensor_names[] = {
    156   1.2  pgoyette 	"l_temp",  "r1_temp", "r2_temp", "Vccp",   "Vcc",    "fan1",
    157   1.4  pgoyette 	"fan2",    "fan3",    "fan4",    "AIN1",   "AIN2",   "V2dot5",
    158   1.4  pgoyette 	"V5",      "V12",     "Vtt",     "Imon"
    159   1.2  pgoyette };
    160   1.2  pgoyette 
    161   1.2  pgoyette /*
    162   1.2  pgoyette  * Following table derived from product data-sheets
    163   1.2  pgoyette  */
    164   1.2  pgoyette static int64_t nominal_voltages[] = {
    165   1.2  pgoyette 	-1,		/* Vcc can be either 3.3 or 5.0V
    166   1.2  pgoyette 			   at 3/4 scale                  */
    167   1.3  pgoyette 	 2249939,	/* Vccp         2.25V 3/4 scale  */
    168   1.3  pgoyette 	 2497436,	/* 2.5VIN       2.5V  3/4 scale  */
    169   1.3  pgoyette 	 5002466,	/* 5VIN         5V    3/4 scale  */
    170   1.2  pgoyette 	12000000,	/* 12VIN       12V    3/4 scale  */
    171   1.3  pgoyette 	 1690809,	/* Vtt, Imon    2.25V full scale */
    172   1.3  pgoyette 	 1689600,	/* AIN1, AIN2   2.25V full scale */
    173   1.3  pgoyette 	       0
    174   1.2  pgoyette };
    175   1.2  pgoyette 
    176   1.2  pgoyette /*
    177   1.2  pgoyette  * Sensor-type, { val-reg, hilim-reg, lolim-reg}, name-idx, sysctl-table-idx,
    178   1.2  pgoyette  *	nom-voltage-index
    179   1.2  pgoyette  */
    180   1.2  pgoyette struct dbcool_sensor ADT7490_sensor_table[] = {
    181   1.2  pgoyette 	{ DBC_TEMP, {	DBCOOL_LOCAL_TEMP,
    182   1.2  pgoyette 			DBCOOL_LOCAL_HIGHLIM,
    183   1.2  pgoyette 			DBCOOL_LOCAL_LOWLIM },		0, 0, 0 },
    184   1.2  pgoyette 	{ DBC_TEMP, {	DBCOOL_REMOTE1_TEMP,
    185   1.2  pgoyette 			DBCOOL_REMOTE1_HIGHLIM,
    186   1.2  pgoyette 			DBCOOL_REMOTE1_LOWLIM },	1, 0, 0 },
    187   1.2  pgoyette 	{ DBC_TEMP, {	DBCOOL_REMOTE2_TEMP,
    188   1.2  pgoyette 			DBCOOL_REMOTE2_HIGHLIM,
    189   1.2  pgoyette 			DBCOOL_REMOTE2_LOWLIM },	2, 0, 0 },
    190   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_VCCP,
    191   1.2  pgoyette 			DBCOOL_VCCP_HIGHLIM,
    192   1.2  pgoyette 			DBCOOL_VCCP_LOWLIM },		3, 0, 1 },
    193   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_VCC,
    194   1.2  pgoyette 			DBCOOL_VCC_HIGHLIM,
    195   1.2  pgoyette 			DBCOOL_VCC_LOWLIM },		4, 0, 0 },
    196   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_25VIN,
    197   1.2  pgoyette 			DBCOOL_25VIN_HIGHLIM,
    198   1.2  pgoyette 			DBCOOL_25VIN_LOWLIM },		11, 0, 2 },
    199   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_5VIN,
    200   1.2  pgoyette 			DBCOOL_5VIN_HIGHLIM,
    201   1.2  pgoyette 			DBCOOL_5VIN_LOWLIM },		12, 0, 3 },
    202   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_12VIN,
    203   1.2  pgoyette 			DBCOOL_12VIN_HIGHLIM,
    204   1.2  pgoyette 			DBCOOL_12VIN_LOWLIM },		13, 0, 4 },
    205   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_VTT,
    206   1.2  pgoyette 			DBCOOL_VTT_HIGHLIM,
    207   1.2  pgoyette 			DBCOOL_VTT_LOWLIM },		14, 0, 5 },
    208   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_IMON,
    209   1.2  pgoyette 			DBCOOL_IMON_HIGHLIM,
    210   1.2  pgoyette 			DBCOOL_IMON_LOWLIM },		15, 0, 5 },
    211   1.2  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN1_TACH_LSB,
    212   1.2  pgoyette 			DBCOOL_NO_REG,
    213   1.2  pgoyette 			DBCOOL_TACH1_MIN_LSB },		5, 0, 0 },
    214   1.2  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN2_TACH_LSB,
    215   1.2  pgoyette 			DBCOOL_NO_REG,
    216   1.2  pgoyette 			DBCOOL_TACH2_MIN_LSB },		6, 0, 0 },
    217   1.2  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN3_TACH_LSB,
    218   1.2  pgoyette 			DBCOOL_NO_REG,
    219   1.2  pgoyette 			DBCOOL_TACH3_MIN_LSB },		7, 0, 0 },
    220   1.2  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN4_TACH_LSB,
    221   1.2  pgoyette 			DBCOOL_NO_REG,
    222   1.2  pgoyette 			DBCOOL_TACH4_MIN_LSB },		8, 0, 0 },
    223   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_LOCAL_TMIN,
    224   1.2  pgoyette 			DBCOOL_NO_REG,
    225   1.2  pgoyette 			DBCOOL_NO_REG },		0, 5, 0 },
    226   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_LOCAL_TTHRESH,
    227   1.2  pgoyette 			DBCOOL_NO_REG,
    228   1.2  pgoyette 			DBCOOL_NO_REG },		0, 6, 0 },
    229   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_R1_LCL_TMIN_HYST | 0x80,
    230   1.2  pgoyette 			DBCOOL_NO_REG,
    231   1.2  pgoyette 			DBCOOL_NO_REG },		0, 7, 0 },
    232   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE1_TMIN,
    233   1.2  pgoyette 			DBCOOL_NO_REG,
    234   1.2  pgoyette 			DBCOOL_NO_REG },		1, 5, 0 },
    235   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE1_TTHRESH,
    236   1.2  pgoyette 			DBCOOL_NO_REG,
    237   1.2  pgoyette 			DBCOOL_NO_REG },		1, 6, 0 },
    238   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_R1_LCL_TMIN_HYST,
    239   1.2  pgoyette 			DBCOOL_NO_REG,
    240   1.2  pgoyette 			DBCOOL_NO_REG },		1, 7, 0 },
    241   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE2_TMIN,
    242   1.2  pgoyette 			DBCOOL_NO_REG,
    243   1.2  pgoyette 			DBCOOL_NO_REG },		2, 5, 0 },
    244   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE2_TTHRESH,
    245   1.2  pgoyette 			DBCOOL_NO_REG,
    246   1.2  pgoyette 			DBCOOL_NO_REG },		2, 6, 0 },
    247   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_R2_TMIN_HYST,
    248   1.2  pgoyette 			DBCOOL_NO_REG,
    249   1.2  pgoyette 			DBCOOL_NO_REG },		2, 7, 0 },
    250   1.2  pgoyette 	{ DBC_EOF,  { 0, 0, 0 }, 0, 0, 0 }
    251   1.2  pgoyette };
    252   1.2  pgoyette 
    253   1.2  pgoyette struct dbcool_sensor ADT7476_sensor_table[] = {
    254   1.2  pgoyette 	{ DBC_TEMP, {	DBCOOL_LOCAL_TEMP,
    255   1.2  pgoyette 			DBCOOL_LOCAL_HIGHLIM,
    256   1.2  pgoyette 			DBCOOL_LOCAL_LOWLIM },		0, 0, 0 },
    257   1.2  pgoyette 	{ DBC_TEMP, {	DBCOOL_REMOTE1_TEMP,
    258   1.2  pgoyette 			DBCOOL_REMOTE1_HIGHLIM,
    259   1.2  pgoyette 			DBCOOL_REMOTE1_LOWLIM },	1, 0, 0 },
    260   1.2  pgoyette 	{ DBC_TEMP, {	DBCOOL_REMOTE2_TEMP,
    261   1.2  pgoyette 			DBCOOL_REMOTE2_HIGHLIM,
    262   1.2  pgoyette 			DBCOOL_REMOTE2_LOWLIM },	2, 0, 0 },
    263   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_VCCP,
    264   1.2  pgoyette 			DBCOOL_VCCP_HIGHLIM,
    265   1.2  pgoyette 			DBCOOL_VCCP_LOWLIM },		3, 0, 1 },
    266   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_VCC,
    267   1.2  pgoyette 			DBCOOL_VCC_HIGHLIM,
    268   1.2  pgoyette 			DBCOOL_VCC_LOWLIM },		4, 0, 0 },
    269   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_25VIN,
    270   1.2  pgoyette 			DBCOOL_25VIN_HIGHLIM,
    271   1.2  pgoyette 			DBCOOL_25VIN_LOWLIM },		11, 0, 2 },
    272   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_5VIN,
    273   1.2  pgoyette 			DBCOOL_5VIN_HIGHLIM,
    274   1.2  pgoyette 			DBCOOL_5VIN_LOWLIM },		12, 0, 3 },
    275   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_12VIN,
    276   1.2  pgoyette 			DBCOOL_12VIN_HIGHLIM,
    277   1.2  pgoyette 			DBCOOL_12VIN_LOWLIM },		13, 0, 4 },
    278   1.2  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN1_TACH_LSB,
    279   1.2  pgoyette 			DBCOOL_NO_REG,
    280   1.2  pgoyette 			DBCOOL_TACH1_MIN_LSB },		5, 0, 0 },
    281   1.2  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN2_TACH_LSB,
    282   1.2  pgoyette 			DBCOOL_NO_REG,
    283   1.2  pgoyette 			DBCOOL_TACH2_MIN_LSB },		6, 0, 0 },
    284   1.2  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN3_TACH_LSB,
    285   1.2  pgoyette 			DBCOOL_NO_REG,
    286   1.2  pgoyette 			DBCOOL_TACH3_MIN_LSB },		7, 0, 0 },
    287   1.2  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN4_TACH_LSB,
    288   1.2  pgoyette 			DBCOOL_NO_REG,
    289   1.2  pgoyette 			DBCOOL_TACH4_MIN_LSB },		8, 0, 0 },
    290   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_LOCAL_TMIN,
    291   1.2  pgoyette 			DBCOOL_NO_REG,
    292   1.2  pgoyette 			DBCOOL_NO_REG },		0, 5, 0 },
    293   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_LOCAL_TTHRESH,
    294   1.2  pgoyette 			DBCOOL_NO_REG,
    295   1.2  pgoyette 			DBCOOL_NO_REG },		0, 6, 0 },
    296   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_R1_LCL_TMIN_HYST | 0x80,
    297   1.2  pgoyette 			DBCOOL_NO_REG,
    298   1.2  pgoyette 			DBCOOL_NO_REG },		0, 7, 0 },
    299   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE1_TMIN,
    300   1.2  pgoyette 			DBCOOL_NO_REG,
    301   1.2  pgoyette 			DBCOOL_NO_REG },		1, 5, 0 },
    302   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE1_TTHRESH,
    303   1.2  pgoyette 			DBCOOL_NO_REG,
    304   1.2  pgoyette 			DBCOOL_NO_REG },		1, 6, 0 },
    305   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_R1_LCL_TMIN_HYST,
    306   1.2  pgoyette 			DBCOOL_NO_REG,
    307   1.2  pgoyette 			DBCOOL_NO_REG },		1, 7, 0 },
    308   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE2_TMIN,
    309   1.2  pgoyette 			DBCOOL_NO_REG,
    310   1.2  pgoyette 			DBCOOL_NO_REG },		2, 5, 0 },
    311   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE2_TTHRESH,
    312   1.2  pgoyette 			DBCOOL_NO_REG,
    313   1.2  pgoyette 			DBCOOL_NO_REG },		2, 6, 0 },
    314   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_R2_TMIN_HYST,
    315   1.2  pgoyette 			DBCOOL_NO_REG,
    316   1.2  pgoyette 			DBCOOL_NO_REG },		2, 7, 0 },
    317   1.2  pgoyette 	{ DBC_EOF,  { 0, 0, 0 }, 0, 0, 0 }
    318   1.1  pgoyette };
    319   1.1  pgoyette 
    320   1.1  pgoyette struct dbcool_sensor ADT7475_sensor_table[] = {
    321   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_LOCAL_TEMP,
    322   1.1  pgoyette 			DBCOOL_LOCAL_HIGHLIM,
    323   1.2  pgoyette 			DBCOOL_LOCAL_LOWLIM },		0, 0, 0 },
    324   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_REMOTE1_TEMP,
    325   1.1  pgoyette 			DBCOOL_REMOTE1_HIGHLIM,
    326   1.2  pgoyette 			DBCOOL_REMOTE1_LOWLIM },	1, 0, 0 },
    327   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_REMOTE2_TEMP,
    328   1.1  pgoyette 			DBCOOL_REMOTE2_HIGHLIM,
    329   1.2  pgoyette 			DBCOOL_REMOTE2_LOWLIM },	2, 0, 0 },
    330   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_VCCP,
    331   1.1  pgoyette 			DBCOOL_VCCP_HIGHLIM,
    332   1.2  pgoyette 			DBCOOL_VCCP_LOWLIM },		3, 0, 1 },
    333   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_VCC,
    334   1.1  pgoyette 			DBCOOL_VCC_HIGHLIM,
    335   1.2  pgoyette 			DBCOOL_VCC_LOWLIM },		4, 0, 0 },
    336   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN1_TACH_LSB,
    337   1.1  pgoyette 			DBCOOL_NO_REG,
    338   1.2  pgoyette 			DBCOOL_TACH1_MIN_LSB },		5, 0, 0 },
    339   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN2_TACH_LSB,
    340   1.1  pgoyette 			DBCOOL_NO_REG,
    341   1.2  pgoyette 			DBCOOL_TACH2_MIN_LSB },		6, 0, 0 },
    342   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN3_TACH_LSB,
    343   1.1  pgoyette 			DBCOOL_NO_REG,
    344   1.2  pgoyette 			DBCOOL_TACH3_MIN_LSB },		7, 0, 0 },
    345   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN4_TACH_LSB,
    346   1.1  pgoyette 			DBCOOL_NO_REG,
    347   1.2  pgoyette 			DBCOOL_TACH4_MIN_LSB },		8, 0, 0 },
    348   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_LOCAL_TMIN,
    349   1.1  pgoyette 			DBCOOL_NO_REG,
    350   1.2  pgoyette 			DBCOOL_NO_REG },		0, 5, 0 },
    351   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_LOCAL_TTHRESH,
    352   1.1  pgoyette 			DBCOOL_NO_REG,
    353   1.2  pgoyette 			DBCOOL_NO_REG },		0, 6, 0 },
    354   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_R1_LCL_TMIN_HYST | 0x80,
    355   1.1  pgoyette 			DBCOOL_NO_REG,
    356   1.2  pgoyette 			DBCOOL_NO_REG },		0, 7, 0 },
    357   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE1_TMIN,
    358   1.1  pgoyette 			DBCOOL_NO_REG,
    359   1.2  pgoyette 			DBCOOL_NO_REG },		1, 5, 0 },
    360   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE1_TTHRESH,
    361   1.1  pgoyette 			DBCOOL_NO_REG,
    362   1.2  pgoyette 			DBCOOL_NO_REG },		1, 6, 0 },
    363   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_R1_LCL_TMIN_HYST,
    364   1.1  pgoyette 			DBCOOL_NO_REG,
    365   1.2  pgoyette 			DBCOOL_NO_REG },		1, 7, 0 },
    366   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE2_TMIN,
    367   1.1  pgoyette 			DBCOOL_NO_REG,
    368   1.2  pgoyette 			DBCOOL_NO_REG },		2, 5, 0 },
    369   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE2_TTHRESH,
    370   1.1  pgoyette 			DBCOOL_NO_REG,
    371   1.2  pgoyette 			DBCOOL_NO_REG },		2, 6, 0 },
    372   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_R2_TMIN_HYST,
    373   1.1  pgoyette 			DBCOOL_NO_REG,
    374   1.2  pgoyette 			DBCOOL_NO_REG },		2, 7, 0 },
    375   1.2  pgoyette 	{ DBC_EOF,  { 0, 0, 0 }, 0, 0, 0 }
    376   1.1  pgoyette };
    377   1.1  pgoyette 
    378   1.1  pgoyette /*
    379   1.2  pgoyette  * The registers of dbcool_power_control must be in the same order as
    380   1.1  pgoyette  * in enum dbc_pwm_params
    381   1.1  pgoyette  */
    382   1.1  pgoyette struct dbcool_power_control ADT7475_power_table[] = {
    383   1.2  pgoyette 	{ { DBCOOL_PWM1_CTL, DBCOOL_PWM1_MINDUTY,
    384   1.2  pgoyette 	    DBCOOL_PWM1_MAXDUTY, DBCOOL_PWM1_CURDUTY },
    385   1.1  pgoyette 		"fan_control_1" },
    386   1.2  pgoyette 	{ { DBCOOL_PWM2_CTL, DBCOOL_PWM2_MINDUTY,
    387   1.2  pgoyette 	    DBCOOL_PWM2_MAXDUTY, DBCOOL_PWM2_CURDUTY },
    388   1.1  pgoyette 		"fan_control_2" },
    389   1.2  pgoyette 	{ { DBCOOL_PWM3_CTL, DBCOOL_PWM3_MINDUTY,
    390   1.2  pgoyette 	    DBCOOL_PWM3_MAXDUTY, DBCOOL_PWM3_CURDUTY },
    391   1.1  pgoyette 		"fan_control_3" },
    392   1.2  pgoyette 	{ { 0, 0, 0, 0 }, NULL }
    393   1.1  pgoyette };
    394   1.1  pgoyette 
    395   1.1  pgoyette struct dbcool_sensor ADT7466_sensor_table[] = {
    396   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_ADT7466_LCL_TEMP_MSB,
    397   1.1  pgoyette 			DBCOOL_ADT7466_LCL_TEMP_HILIM,
    398   1.2  pgoyette 			DBCOOL_ADT7466_LCL_TEMP_LOLIM }, 0,  0, 0 },
    399   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_ADT7466_REM_TEMP_MSB,
    400   1.1  pgoyette 			DBCOOL_ADT7466_REM_TEMP_HILIM,
    401   1.2  pgoyette 			DBCOOL_ADT7466_REM_TEMP_LOLIM }, 1,  0, 0 },
    402   1.1  pgoyette 	{ DBC_VOLT, {	DBCOOL_ADT7466_VCC,
    403   1.1  pgoyette 			DBCOOL_ADT7466_VCC_HILIM,
    404   1.2  pgoyette 			DBCOOL_ADT7466_VCC_LOLIM },	4,  0, 0 },
    405   1.1  pgoyette 	{ DBC_VOLT, {	DBCOOL_ADT7466_AIN1,
    406   1.1  pgoyette 			DBCOOL_ADT7466_AIN1_HILIM,
    407   1.2  pgoyette 			DBCOOL_ADT7466_AIN1_LOLIM },	9,  0, 6 },
    408   1.1  pgoyette 	{ DBC_VOLT, {	DBCOOL_ADT7466_AIN2,
    409   1.1  pgoyette 			DBCOOL_ADT7466_AIN2_HILIM,
    410   1.2  pgoyette 			DBCOOL_ADT7466_AIN2_LOLIM },	10, 0, 6 },
    411   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_ADT7466_FANA_LSB,
    412   1.1  pgoyette 			DBCOOL_NO_REG,
    413   1.2  pgoyette 			DBCOOL_ADT7466_FANA_LOLIM_LSB }, 5,  0, 0 },
    414   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_ADT7466_FANB_LSB,
    415   1.1  pgoyette 			DBCOOL_NO_REG,
    416   1.2  pgoyette 			DBCOOL_ADT7466_FANB_LOLIM_LSB }, 6,  0, 0 },
    417   1.2  pgoyette 	{ DBC_EOF,  { 0, 0, 0 }, 0, 0, 0 }
    418   1.1  pgoyette };
    419   1.1  pgoyette 
    420   1.1  pgoyette struct dbcool_sensor ADM1027_sensor_table[] = {
    421   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_LOCAL_TEMP,
    422   1.1  pgoyette 			DBCOOL_LOCAL_HIGHLIM,
    423   1.2  pgoyette 			DBCOOL_LOCAL_LOWLIM },		0, 0, 0 },
    424   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_REMOTE1_TEMP,
    425   1.1  pgoyette 			DBCOOL_REMOTE1_HIGHLIM,
    426   1.2  pgoyette 			DBCOOL_REMOTE1_LOWLIM },	1, 0, 0 },
    427   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_REMOTE2_TEMP,
    428   1.1  pgoyette 			DBCOOL_REMOTE2_HIGHLIM,
    429   1.2  pgoyette 			DBCOOL_REMOTE2_LOWLIM },	2, 0, 0 },
    430   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_VCCP,
    431   1.1  pgoyette 			DBCOOL_VCCP_HIGHLIM,
    432   1.2  pgoyette 			DBCOOL_VCCP_LOWLIM },		3, 0, 1 },
    433   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_VCC,
    434   1.1  pgoyette 			DBCOOL_VCC_HIGHLIM,
    435   1.2  pgoyette 			DBCOOL_VCC_LOWLIM },		4, 0, 0 },
    436   1.1  pgoyette 	{ DBC_VOLT, {	DBCOOL_25VIN,
    437   1.1  pgoyette 			DBCOOL_25VIN_HIGHLIM,
    438   1.2  pgoyette 			DBCOOL_25VIN_LOWLIM },		11, 0, 2 },
    439   1.1  pgoyette 	{ DBC_VOLT, {	DBCOOL_5VIN,
    440   1.1  pgoyette 			DBCOOL_5VIN_HIGHLIM,
    441   1.2  pgoyette 			DBCOOL_5VIN_LOWLIM },		12, 0, 3 },
    442   1.1  pgoyette 	{ DBC_VOLT, {	DBCOOL_12VIN,
    443   1.1  pgoyette 			DBCOOL_12VIN_HIGHLIM,
    444   1.2  pgoyette 			DBCOOL_12VIN_LOWLIM },		13, 0, 4 },
    445   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN1_TACH_LSB,
    446   1.1  pgoyette 			DBCOOL_NO_REG,
    447   1.2  pgoyette 			DBCOOL_TACH1_MIN_LSB },		5, 0, 0 },
    448   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN2_TACH_LSB,
    449   1.1  pgoyette 			DBCOOL_NO_REG,
    450   1.2  pgoyette 			DBCOOL_TACH2_MIN_LSB },		6, 0, 0 },
    451   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN3_TACH_LSB,
    452   1.1  pgoyette 			DBCOOL_NO_REG,
    453   1.2  pgoyette 			DBCOOL_TACH3_MIN_LSB },		7, 0, 0 },
    454   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN4_TACH_LSB,
    455   1.1  pgoyette 			DBCOOL_NO_REG,
    456   1.2  pgoyette 			DBCOOL_TACH4_MIN_LSB },		8, 0, 0 },
    457   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_LOCAL_TMIN,
    458   1.1  pgoyette 			DBCOOL_NO_REG,
    459   1.2  pgoyette 			DBCOOL_NO_REG },		0, 5, 0 },
    460   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_LOCAL_TTHRESH,
    461   1.1  pgoyette 			DBCOOL_NO_REG,
    462   1.2  pgoyette 			DBCOOL_NO_REG },		0, 6, 0 },
    463   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_R1_LCL_TMIN_HYST | 0x80,
    464   1.1  pgoyette 			DBCOOL_NO_REG,
    465   1.2  pgoyette 			DBCOOL_NO_REG },		0, 7, 0 },
    466   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE1_TMIN,
    467   1.1  pgoyette 			DBCOOL_NO_REG,
    468   1.2  pgoyette 			DBCOOL_NO_REG },		1, 5, 0 },
    469   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE1_TTHRESH,
    470   1.1  pgoyette 			DBCOOL_NO_REG,
    471   1.2  pgoyette 			DBCOOL_NO_REG },		1, 6, 0 },
    472   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_R1_LCL_TMIN_HYST,
    473   1.1  pgoyette 			DBCOOL_NO_REG,
    474   1.2  pgoyette 			DBCOOL_NO_REG },		1, 7, 0 },
    475   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE2_TMIN,
    476   1.1  pgoyette 			DBCOOL_NO_REG,
    477   1.2  pgoyette 			DBCOOL_NO_REG },		2, 5, 0 },
    478   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE2_TTHRESH,
    479   1.1  pgoyette 			DBCOOL_NO_REG,
    480   1.2  pgoyette 			DBCOOL_NO_REG },		2, 6, 0 },
    481   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_R2_TMIN_HYST,
    482   1.1  pgoyette 			DBCOOL_NO_REG,
    483   1.2  pgoyette 			DBCOOL_NO_REG },		2, 7, 0 },
    484   1.2  pgoyette 	{ DBC_EOF,  { 0, 0, 0 }, 0, 0, 0 }
    485   1.1  pgoyette };
    486   1.1  pgoyette 
    487   1.1  pgoyette struct dbcool_sensor ADM1030_sensor_table[] = {
    488   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_ADM1030_L_TEMP,
    489   1.1  pgoyette 			DBCOOL_ADM1030_L_HI_LIM,
    490   1.2  pgoyette 			DBCOOL_ADM1030_L_LO_LIM },	0,  0, 0 },
    491   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_ADM1030_R_TEMP,
    492   1.1  pgoyette 			DBCOOL_ADM1030_R_HI_LIM,
    493   1.2  pgoyette 			DBCOOL_ADM1030_R_LO_LIM },	1,  0, 0 },
    494   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_ADM1030_FAN_TACH,
    495   1.1  pgoyette 			DBCOOL_NO_REG,
    496   1.2  pgoyette 			DBCOOL_ADM1030_FAN_LO_LIM },	5,  0, 0 },
    497   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_ADM1030_L_TMIN,
    498   1.1  pgoyette 			DBCOOL_NO_REG,
    499   1.2  pgoyette 			DBCOOL_NO_REG },		0,  8, 0 },
    500   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_ADM1030_L_TTHRESH,
    501   1.1  pgoyette 			DBCOOL_NO_REG,
    502   1.2  pgoyette 			DBCOOL_NO_REG },		0,  9, 0 },
    503   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_ADM1030_L_TTHRESH,
    504   1.1  pgoyette 			DBCOOL_NO_REG,
    505   1.2  pgoyette 			DBCOOL_NO_REG },		0,  6, 0 },
    506   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_ADM1030_R_TMIN,
    507   1.1  pgoyette 			DBCOOL_NO_REG,
    508   1.2  pgoyette 			DBCOOL_NO_REG },		1,  8, 0 },
    509   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_ADM1030_L_TTHRESH,
    510   1.1  pgoyette 			DBCOOL_NO_REG,
    511   1.2  pgoyette 			DBCOOL_NO_REG },		1,  9, 0 },
    512   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_ADM1030_R_TTHRESH,
    513   1.1  pgoyette 			DBCOOL_NO_REG,
    514   1.2  pgoyette 			DBCOOL_NO_REG },		1,  6, 0 },
    515   1.2  pgoyette 	{ DBC_EOF,  {0, 0, 0 }, 0, 0, 0 }
    516   1.1  pgoyette };
    517   1.1  pgoyette 
    518   1.1  pgoyette struct dbcool_power_control ADM1030_power_table[] = {
    519   1.2  pgoyette 	{ { DBCOOL_ADM1030_CFG1,  DBCOOL_NO_REG, DBCOOL_NO_REG,
    520   1.2  pgoyette 	    DBCOOL_ADM1030_FAN_SPEED_CFG },
    521   1.2  pgoyette 	  "fan_control_1" },
    522   1.2  pgoyette 	{ { 0, 0, 0, 0 }, NULL }
    523   1.1  pgoyette };
    524   1.1  pgoyette 
    525   1.1  pgoyette struct chip_id chip_table[] = {
    526   1.2  pgoyette 	{ DBCOOL_COMPANYID, ADT7490_DEVICEID, ADT7490_REV_ID,
    527   1.2  pgoyette 		ADT7475_sensor_table, ADT7475_power_table,
    528   1.2  pgoyette 		DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_VID |
    529   1.2  pgoyette 			DBCFLAG_HAS_PECI,
    530   1.2  pgoyette 		90000 * 60, "ADT7490" },
    531   1.1  pgoyette 	{ DBCOOL_COMPANYID, ADT7476_DEVICEID, 0xff,
    532   1.2  pgoyette 		ADT7476_sensor_table, ADT7475_power_table,
    533   1.1  pgoyette 		DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_VID,
    534   1.1  pgoyette 		90000 * 60, "ADT7476" },
    535   1.1  pgoyette 	{ DBCOOL_COMPANYID, ADT7475_DEVICEID, 0xff,
    536   1.1  pgoyette 		ADT7475_sensor_table, ADT7475_power_table,
    537   1.1  pgoyette 		DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_SHDN,
    538   1.1  pgoyette 		90000 * 60, "ADT7475" },
    539   1.2  pgoyette 	{ DBCOOL_COMPANYID, ADT7473_DEVICEID, ADT7473_REV_ID1,
    540   1.1  pgoyette 		ADT7475_sensor_table, ADT7475_power_table,
    541   1.1  pgoyette 		DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_SHDN,
    542   1.8  pgoyette 		90000 * 60, "ADT7460/ADT7463" },
    543   1.2  pgoyette 	{ DBCOOL_COMPANYID, ADT7473_DEVICEID, ADT7473_REV_ID2,
    544   1.1  pgoyette 		ADT7475_sensor_table, ADT7475_power_table,
    545   1.1  pgoyette 		DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_SHDN,
    546   1.1  pgoyette 		90000 * 60, "ADT7463-1" },
    547   1.1  pgoyette 	{ DBCOOL_COMPANYID, ADT7468_DEVICEID, 0xff,
    548   1.2  pgoyette 		ADT7476_sensor_table, ADT7475_power_table,
    549   1.1  pgoyette 		DBCFLAG_TEMPOFFSET  | DBCFLAG_MULTI_VCC | DBCFLAG_HAS_MAXDUTY |
    550   1.1  pgoyette 		    DBCFLAG_4BIT_VER | DBCFLAG_HAS_SHDN | DBCFLAG_HAS_VID,
    551   1.2  pgoyette 		90000 * 60, "ADT7467/ADT7468" },
    552   1.1  pgoyette 	{ DBCOOL_COMPANYID, ADT7466_DEVICEID, 0xff,
    553   1.1  pgoyette 		ADT7466_sensor_table, NULL,
    554   1.1  pgoyette 		DBCFLAG_ADT7466 | DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_SHDN,
    555   1.1  pgoyette 		82000 * 60, "ADT7466" },
    556   1.1  pgoyette 	{ DBCOOL_COMPANYID, ADT7463_DEVICEID, ADT7463_REV_ID1,
    557   1.1  pgoyette 		ADM1027_sensor_table, ADT7475_power_table,
    558   1.1  pgoyette 		DBCFLAG_MULTI_VCC | DBCFLAG_4BIT_VER | DBCFLAG_HAS_SHDN |
    559   1.1  pgoyette 		    DBCFLAG_ADM1027 | DBCFLAG_HAS_VID,
    560   1.1  pgoyette 		90000 * 60, "ADT7463" },
    561   1.1  pgoyette 	{ DBCOOL_COMPANYID, ADT7463_DEVICEID, ADT7463_REV_ID2,
    562   1.1  pgoyette 		ADM1027_sensor_table, ADT7475_power_table,
    563   1.1  pgoyette 		DBCFLAG_MULTI_VCC | DBCFLAG_4BIT_VER | DBCFLAG_HAS_SHDN |
    564   1.2  pgoyette 		    DBCFLAG_HAS_VID | DBCFLAG_HAS_VID_SEL,
    565   1.1  pgoyette 		90000 * 60, "ADT7463" },
    566   1.1  pgoyette 	{ DBCOOL_COMPANYID, ADM1027_DEVICEID, ADM1027_REV_ID,
    567   1.1  pgoyette 		ADM1027_sensor_table, ADT7475_power_table,
    568   1.2  pgoyette 		DBCFLAG_MULTI_VCC | DBCFLAG_4BIT_VER | DBCFLAG_HAS_VID,
    569   1.1  pgoyette 		90000 * 60, "ADM1027" },
    570   1.1  pgoyette 	{ DBCOOL_COMPANYID, ADM1030_DEVICEID, 0xff,
    571   1.1  pgoyette 		ADM1030_sensor_table, ADM1030_power_table,
    572   1.1  pgoyette 		DBCFLAG_ADM1030,
    573   1.1  pgoyette 		11250 * 60, "ADM1030" },
    574   1.1  pgoyette 	{ 0, 0, 0, NULL, NULL, 0, 0, NULL }
    575   1.1  pgoyette };
    576   1.1  pgoyette 
    577   1.1  pgoyette static const char *behavior[] = {
    578   1.1  pgoyette 	"remote1",	"local",	"remote2",	"full-speed",
    579   1.1  pgoyette 	"disabled",	"local+remote2","all-temps",	"manual"
    580   1.1  pgoyette };
    581   1.1  pgoyette 
    582   1.1  pgoyette static char dbcool_cur_behav[16];
    583   1.1  pgoyette 
    584   1.1  pgoyette CFATTACH_DECL_NEW(dbcool, sizeof(struct dbcool_softc),
    585   1.1  pgoyette     dbcool_match, dbcool_attach, dbcool_detach, NULL);
    586   1.1  pgoyette 
    587   1.1  pgoyette int
    588   1.1  pgoyette dbcool_match(device_t parent, cfdata_t cf, void *aux)
    589   1.1  pgoyette {
    590   1.1  pgoyette 	struct i2c_attach_args *ia = aux;
    591  1.13  christos 	struct dbcool_chipset dc;
    592  1.13  christos 	dc.dc_tag = ia->ia_tag;
    593  1.13  christos 	dc.dc_addr = ia->ia_addr;
    594  1.13  christos 	dc.dc_chip = NULL;
    595  1.13  christos 	dc.dc_readreg = dbcool_readreg;
    596  1.13  christos 	dc.dc_writereg = dbcool_writereg;
    597   1.1  pgoyette 
    598   1.7  pgoyette 	/* no probing if we attach to iic, but verify chip id  and address */
    599   1.7  pgoyette 	if ((ia->ia_addr & DBCOOL_ADDRMASK) != DBCOOL_ADDR)
    600   1.7  pgoyette 		return 0;
    601  1.13  christos 	if (dbcool_chip_ident(&dc) >= 0)
    602   1.1  pgoyette 		return 1;
    603   1.1  pgoyette 
    604   1.1  pgoyette 	return 0;
    605   1.1  pgoyette }
    606   1.1  pgoyette 
    607   1.1  pgoyette void
    608   1.1  pgoyette dbcool_attach(device_t parent, device_t self, void *aux)
    609   1.1  pgoyette {
    610   1.1  pgoyette 	struct dbcool_softc *sc = device_private(self);
    611   1.1  pgoyette 	struct i2c_attach_args *args = aux;
    612   1.1  pgoyette 	uint8_t ver;
    613   1.1  pgoyette 
    614  1.13  christos 	sc->sc_dc.dc_addr = args->ia_addr;
    615  1.13  christos 	sc->sc_dc.dc_tag = args->ia_tag;
    616  1.13  christos 	sc->sc_dc.dc_chip = NULL;
    617  1.13  christos 	sc->sc_dc.dc_readreg = dbcool_readreg;
    618  1.13  christos 	sc->sc_dc.dc_writereg = dbcool_writereg;
    619  1.13  christos 	(void)dbcool_chip_ident(&sc->sc_dc);
    620   1.2  pgoyette 	sc->sc_dev = self;
    621   1.1  pgoyette 
    622   1.1  pgoyette 	aprint_naive("\n");
    623   1.1  pgoyette 	aprint_normal("\n");
    624   1.1  pgoyette 
    625  1.13  christos 	ver = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_REVISION_REG);
    626  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_4BIT_VER)
    627   1.1  pgoyette 		aprint_normal_dev(self, "%s dBCool(tm) Controller "
    628  1.13  christos 			"(rev 0x%02x, stepping 0x%02x)\n", sc->sc_dc.dc_chip->name,
    629   1.1  pgoyette 			ver >> 4, ver & 0x0f);
    630   1.1  pgoyette 	else
    631   1.1  pgoyette 		aprint_normal_dev(self, "%s dBCool(tm) Controller "
    632  1.13  christos 			"(rev 0x%04x)\n", sc->sc_dc.dc_chip->name, ver);
    633   1.1  pgoyette 
    634   1.1  pgoyette 	dbcool_setup(self);
    635   1.1  pgoyette 
    636   1.1  pgoyette 	if (!pmf_device_register(self, dbcool_pmf_suspend, dbcool_pmf_resume))
    637   1.1  pgoyette 		aprint_error_dev(self, "couldn't establish power handler\n");
    638   1.1  pgoyette }
    639   1.1  pgoyette 
    640   1.1  pgoyette static int
    641   1.1  pgoyette dbcool_detach(device_t self, int flags)
    642   1.1  pgoyette {
    643   1.1  pgoyette 	struct dbcool_softc *sc = device_private(self);
    644   1.1  pgoyette 
    645   1.1  pgoyette 	sysmon_envsys_unregister(sc->sc_sme);
    646   1.1  pgoyette 	sc->sc_sme = NULL;
    647   1.1  pgoyette 	return 0;
    648   1.1  pgoyette }
    649   1.1  pgoyette 
    650   1.1  pgoyette /* On suspend, we save the state of the SHDN bit, then set it */
    651  1.15    dyoung bool dbcool_pmf_suspend(device_t dev, const pmf_qual_t *qual)
    652   1.1  pgoyette {
    653   1.1  pgoyette 	struct dbcool_softc *sc = device_private(dev);
    654   1.1  pgoyette 	uint8_t reg, bit, cfg;
    655   1.1  pgoyette 
    656  1.13  christos 	if ((sc->sc_dc.dc_chip->flags && DBCFLAG_HAS_SHDN) == 0)
    657   1.1  pgoyette 		return true;
    658   1.1  pgoyette 
    659  1.13  christos 	if (sc->sc_dc.dc_chip->flags && DBCFLAG_ADT7466) {
    660   1.1  pgoyette 		reg = DBCOOL_ADT7466_CONFIG2;
    661   1.1  pgoyette 		bit = DBCOOL_ADT7466_CFG2_SHDN;
    662   1.1  pgoyette 	} else {
    663   1.1  pgoyette 		reg = DBCOOL_CONFIG2_REG;
    664   1.1  pgoyette 		bit = DBCOOL_CFG2_SHDN;
    665   1.1  pgoyette 	}
    666  1.13  christos 	cfg = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
    667   1.1  pgoyette 	sc->sc_suspend = cfg & bit;
    668   1.1  pgoyette 	cfg |= bit;
    669  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, reg, cfg);
    670   1.1  pgoyette 
    671   1.1  pgoyette 	return true;
    672   1.1  pgoyette }
    673   1.1  pgoyette 
    674   1.1  pgoyette /* On resume, we restore the previous state of the SHDN bit */
    675  1.15    dyoung bool dbcool_pmf_resume(device_t dev, const pmf_qual_t *qual)
    676   1.1  pgoyette {
    677   1.1  pgoyette 	struct dbcool_softc *sc = device_private(dev);
    678   1.1  pgoyette 	uint8_t reg, bit, cfg;
    679   1.1  pgoyette 
    680  1.13  christos 	if ((sc->sc_dc.dc_chip->flags && DBCFLAG_HAS_SHDN) == 0)
    681   1.1  pgoyette 		return true;
    682   1.1  pgoyette 
    683  1.13  christos 	if (sc->sc_dc.dc_chip->flags && DBCFLAG_ADT7466) {
    684   1.1  pgoyette 		reg = DBCOOL_ADT7466_CONFIG2;
    685   1.1  pgoyette 		bit = DBCOOL_ADT7466_CFG2_SHDN;
    686   1.1  pgoyette 	} else {
    687   1.1  pgoyette 		reg = DBCOOL_CONFIG2_REG;
    688   1.1  pgoyette 		bit = DBCOOL_CFG2_SHDN;
    689   1.1  pgoyette 	}
    690  1.13  christos 	cfg = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
    691   1.1  pgoyette 	cfg &= ~sc->sc_suspend;
    692  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, reg, cfg);
    693   1.1  pgoyette 
    694   1.1  pgoyette 	return true;
    695   1.1  pgoyette 
    696   1.1  pgoyette }
    697   1.1  pgoyette 
    698   1.1  pgoyette uint8_t
    699  1.13  christos dbcool_readreg(struct dbcool_chipset *dc, uint8_t reg)
    700   1.1  pgoyette {
    701   1.1  pgoyette 	uint8_t data = 0;
    702   1.1  pgoyette 
    703  1.13  christos 	if (iic_acquire_bus(dc->dc_tag, 0) != 0)
    704  1.11  pgoyette 		return data;
    705   1.1  pgoyette 
    706  1.13  christos 	if (dc->dc_chip == NULL || dc->dc_chip->flags & DBCFLAG_ADM1027) {
    707  1.10  pgoyette 		/* ADM1027 doesn't support i2c read_byte protocol */
    708  1.13  christos 		if (iic_smbus_send_byte(dc->dc_tag, dc->dc_addr, reg, 0) != 0)
    709  1.10  pgoyette 			goto bad;
    710  1.13  christos 		(void)iic_smbus_receive_byte(dc->dc_tag, dc->dc_addr, &data, 0);
    711  1.10  pgoyette 	} else
    712  1.13  christos 		(void)iic_smbus_read_byte(dc->dc_tag, dc->dc_addr, reg, &data,
    713  1.10  pgoyette 					  0);
    714   1.1  pgoyette 
    715   1.1  pgoyette bad:
    716  1.13  christos 	iic_release_bus(dc->dc_tag, 0);
    717   1.1  pgoyette 	return data;
    718   1.1  pgoyette }
    719   1.1  pgoyette 
    720   1.1  pgoyette void
    721  1.13  christos dbcool_writereg(struct dbcool_chipset *dc, uint8_t reg, uint8_t val)
    722   1.1  pgoyette {
    723  1.13  christos 	if (iic_acquire_bus(dc->dc_tag, 0) != 0)
    724   1.9  pgoyette 		return;
    725   1.1  pgoyette 
    726  1.13  christos 	(void)iic_smbus_write_byte(dc->dc_tag, dc->dc_addr, reg, val, 0);
    727   1.1  pgoyette 
    728  1.13  christos 	iic_release_bus(dc->dc_tag, 0);
    729   1.1  pgoyette }
    730   1.1  pgoyette 
    731   1.2  pgoyette static bool
    732   1.1  pgoyette dbcool_islocked(struct dbcool_softc *sc)
    733   1.1  pgoyette {
    734   1.1  pgoyette 	uint8_t cfg_reg;
    735   1.1  pgoyette 
    736  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
    737   1.1  pgoyette 		return 0;
    738   1.1  pgoyette 
    739  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466)
    740   1.1  pgoyette 		cfg_reg = DBCOOL_ADT7466_CONFIG1;
    741   1.1  pgoyette 	else
    742   1.1  pgoyette 		cfg_reg = DBCOOL_CONFIG1_REG;
    743   1.1  pgoyette 
    744  1.13  christos 	if (sc->sc_dc.dc_readreg(&sc->sc_dc, cfg_reg) & DBCOOL_CFG1_LOCK)
    745   1.1  pgoyette 		return 1;
    746   1.1  pgoyette 	else
    747   1.1  pgoyette 		return 0;
    748   1.1  pgoyette }
    749   1.1  pgoyette 
    750   1.1  pgoyette static int
    751   1.1  pgoyette dbcool_read_temp(struct dbcool_softc *sc, uint8_t reg, bool extres)
    752   1.1  pgoyette {
    753   1.1  pgoyette 	uint8_t	t1, t2, t3, val, ext = 0;
    754   1.1  pgoyette 	int temp;
    755   1.1  pgoyette 
    756  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) {
    757   1.1  pgoyette 		/*
    758   1.1  pgoyette 		 * ADT7466 temps are in strange location
    759   1.1  pgoyette 		 */
    760  1.13  christos 		ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADT7466_CONFIG1);
    761  1.13  christos 		val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
    762   1.1  pgoyette 		if (extres)
    763  1.13  christos 			ext = sc->sc_dc.dc_readreg(&sc->sc_dc, reg + 1);
    764  1.13  christos 	} else if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) {
    765   1.1  pgoyette 		/*
    766   1.1  pgoyette 		 * ADM1030 temps are in their own special place, too
    767   1.1  pgoyette 		 */
    768   1.1  pgoyette 		if (extres) {
    769  1.13  christos 			ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_TEMP_EXTRES);
    770   1.1  pgoyette 			if (reg == DBCOOL_ADM1030_L_TEMP)
    771   1.1  pgoyette 				ext >>= 6;
    772   1.1  pgoyette 			else
    773   1.1  pgoyette 				ext >>= 1;
    774   1.1  pgoyette 			ext &= 0x03;
    775   1.1  pgoyette 		}
    776  1.13  christos 		val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
    777   1.2  pgoyette 	} else if (extres) {
    778  1.13  christos 		ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES2_REG);
    779   1.1  pgoyette 
    780   1.2  pgoyette 		/* Read all msb regs to unlatch them */
    781  1.13  christos 		t1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_12VIN);
    782  1.13  christos 		t1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_REMOTE1_TEMP);
    783  1.13  christos 		t2 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_REMOTE2_TEMP);
    784  1.13  christos 		t3 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_LOCAL_TEMP);
    785   1.2  pgoyette 		switch (reg) {
    786   1.2  pgoyette 		case DBCOOL_REMOTE1_TEMP:
    787   1.2  pgoyette 			val = t1;
    788   1.2  pgoyette 			ext >>= 2;
    789   1.2  pgoyette 			break;
    790   1.2  pgoyette 		case DBCOOL_LOCAL_TEMP:
    791   1.2  pgoyette 			val = t3;
    792   1.2  pgoyette 			ext >>= 4;
    793   1.2  pgoyette 			break;
    794   1.2  pgoyette 		case DBCOOL_REMOTE2_TEMP:
    795   1.2  pgoyette 			val = t2;
    796   1.2  pgoyette 			ext >>= 6;
    797   1.2  pgoyette 			break;
    798   1.2  pgoyette 		default:
    799   1.2  pgoyette 			val = 0;
    800   1.2  pgoyette 			break;
    801   1.1  pgoyette 		}
    802   1.2  pgoyette 		ext &= 0x03;
    803   1.1  pgoyette 	}
    804   1.2  pgoyette 	else
    805  1.13  christos 		val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
    806   1.1  pgoyette 
    807   1.1  pgoyette 	/* Check for invalid temp values */
    808   1.2  pgoyette 	if ((sc->sc_temp_offset == 0 && val == 0x80) ||
    809   1.2  pgoyette 	    (sc->sc_temp_offset != 0 && val == 0))
    810   1.1  pgoyette 		return 0;
    811   1.1  pgoyette 
    812   1.1  pgoyette 	/* If using offset mode, adjust, else treat as signed */
    813   1.2  pgoyette 	if (sc->sc_temp_offset) {
    814   1.1  pgoyette 		temp = val;
    815   1.2  pgoyette 		temp -= sc->sc_temp_offset;
    816   1.1  pgoyette 	} else
    817   1.1  pgoyette 		temp = (int8_t)val;
    818   1.1  pgoyette 
    819   1.1  pgoyette 	/* Convert degC to uK and include extended precision bits */
    820   1.1  pgoyette 	temp *= 1000000;
    821   1.1  pgoyette 	temp +=  250000 * (int)ext;
    822   1.1  pgoyette 	temp += 273150000U;
    823   1.1  pgoyette 
    824   1.1  pgoyette 	return temp;
    825   1.1  pgoyette }
    826   1.1  pgoyette 
    827   1.1  pgoyette static int
    828   1.1  pgoyette dbcool_read_rpm(struct dbcool_softc *sc, uint8_t reg)
    829   1.1  pgoyette {
    830   1.1  pgoyette 	int rpm;
    831   1.1  pgoyette 	uint8_t rpm_lo, rpm_hi;
    832   1.1  pgoyette 
    833  1.13  christos 	rpm_lo = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
    834  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
    835   1.1  pgoyette 		rpm_hi = (rpm_lo == 0xff)?0xff:0x0;
    836   1.1  pgoyette 	else
    837  1.13  christos 		rpm_hi = sc->sc_dc.dc_readreg(&sc->sc_dc, reg + 1);
    838   1.1  pgoyette 
    839   1.1  pgoyette 	rpm = (rpm_hi << 8) | rpm_lo;
    840   1.1  pgoyette 	if (rpm == 0xffff)
    841   1.1  pgoyette 		return 0;	/* 0xffff indicates stalled/failed fan */
    842   1.1  pgoyette 
    843  1.13  christos 	return (sc->sc_dc.dc_chip->rpm_dividend / rpm);
    844   1.1  pgoyette }
    845   1.1  pgoyette 
    846   1.2  pgoyette /* Provide chip's supply voltage, in microvolts */
    847   1.1  pgoyette static int
    848   1.1  pgoyette dbcool_supply_voltage(struct dbcool_softc *sc)
    849   1.1  pgoyette {
    850  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_MULTI_VCC) {
    851  1.13  christos 		if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_CONFIG1_REG) & DBCOOL_CFG1_Vcc)
    852   1.2  pgoyette 			return 5002500;
    853   1.1  pgoyette 		else
    854   1.2  pgoyette 			return 3300000;
    855  1.13  christos 	} else if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) {
    856  1.13  christos 		if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADT7466_CONFIG1) &
    857   1.1  pgoyette 			    DBCOOL_ADT7466_CFG1_Vcc)
    858   1.2  pgoyette 			return 5000000;
    859   1.1  pgoyette 		else
    860   1.2  pgoyette 			return 3300000;
    861   1.1  pgoyette 	} else
    862   1.2  pgoyette 		return 3300000;
    863   1.1  pgoyette }
    864   1.1  pgoyette 
    865   1.2  pgoyette /*
    866   1.2  pgoyette  * Nominal voltages are calculated in microvolts
    867   1.2  pgoyette  */
    868   1.1  pgoyette static int
    869   1.2  pgoyette dbcool_read_volt(struct dbcool_softc *sc, uint8_t reg, int nom_idx, bool extres)
    870   1.1  pgoyette {
    871   1.1  pgoyette 	uint8_t ext = 0, v1, v2, v3, v4, val;
    872   1.2  pgoyette 	int64_t ret;
    873   1.2  pgoyette 	int64_t nom;
    874   1.2  pgoyette 
    875   1.2  pgoyette 	nom = nominal_voltages[nom_idx];
    876   1.2  pgoyette 	if (nom < 0)
    877   1.2  pgoyette 		nom = sc->sc_supply_voltage;
    878   1.1  pgoyette 
    879   1.1  pgoyette 	/* ADT7466 voltages are in strange locations with only 8-bits */
    880  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466)
    881  1.13  christos 		val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
    882   1.2  pgoyette 	else
    883   1.2  pgoyette 	/*
    884   1.2  pgoyette 	 * It's a "normal" dbCool chip - check for regs that
    885   1.2  pgoyette 	 * share extended resolution bits since we have to
    886   1.2  pgoyette 	 * read all the MSB registers to unlatch them.
    887   1.2  pgoyette 	 */
    888   1.2  pgoyette 	if (!extres)
    889  1.13  christos 		val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
    890   1.2  pgoyette 	else if (reg == DBCOOL_12VIN) {
    891  1.13  christos 		ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES2_REG) && 0x03;
    892  1.13  christos 		val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
    893   1.2  pgoyette 		(void)dbcool_read_temp(sc, DBCOOL_LOCAL_TEMP, true);
    894   1.2  pgoyette 	} else if (reg == DBCOOL_VTT || reg == DBCOOL_IMON) {
    895  1.13  christos 		ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES_VTT_IMON);
    896  1.13  christos 		v1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_IMON);
    897  1.13  christos 		v2 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_VTT);
    898   1.2  pgoyette 		if (reg == DBCOOL_IMON) {
    899   1.2  pgoyette 			val = v1;
    900   1.2  pgoyette 			ext >>= 6;
    901   1.2  pgoyette 		} else
    902   1.2  pgoyette 			val = v2;
    903   1.2  pgoyette 			ext >>= 4;
    904   1.2  pgoyette 		ext &= 0x0f;
    905   1.1  pgoyette 	} else {
    906  1.13  christos 		ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES1_REG);
    907  1.13  christos 		v1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_25VIN);
    908  1.13  christos 		v2 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_VCCP);
    909  1.13  christos 		v3 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_VCC);
    910  1.13  christos 		v4 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_5VIN);
    911   1.1  pgoyette 
    912   1.1  pgoyette 		switch (reg) {
    913   1.1  pgoyette 		case DBCOOL_25VIN:
    914   1.1  pgoyette 			val = v1;
    915   1.1  pgoyette 			break;
    916   1.2  pgoyette 		case DBCOOL_VCCP:
    917   1.1  pgoyette 			val = v2;
    918   1.1  pgoyette 			ext >>= 2;
    919   1.1  pgoyette 			break;
    920   1.2  pgoyette 		case DBCOOL_VCC:
    921   1.1  pgoyette 			val = v3;
    922   1.1  pgoyette 			ext >>= 4;
    923   1.1  pgoyette 			break;
    924   1.1  pgoyette 		case DBCOOL_5VIN:
    925   1.1  pgoyette 			val = v4;
    926   1.1  pgoyette 			ext >>= 6;
    927   1.1  pgoyette 			break;
    928   1.1  pgoyette 		default:
    929   1.1  pgoyette 			val = nom = 0;
    930   1.1  pgoyette 		}
    931   1.1  pgoyette 		ext &= 0x03;
    932   1.1  pgoyette 	}
    933   1.1  pgoyette 
    934   1.1  pgoyette 	/*
    935   1.1  pgoyette 	 * Scale the nominal value by the 10-bit fraction
    936   1.2  pgoyette 	 *
    937   1.1  pgoyette 	 * Returned value is in microvolts.
    938   1.1  pgoyette 	 */
    939   1.2  pgoyette 	ret = val;
    940   1.2  pgoyette 	ret <<= 2;
    941   1.2  pgoyette 	ret |= ext;
    942   1.1  pgoyette 	ret = (ret * nom) / 0x300;
    943   1.1  pgoyette 
    944   1.1  pgoyette 	return ret;
    945   1.1  pgoyette }
    946   1.1  pgoyette 
    947   1.1  pgoyette SYSCTL_SETUP(sysctl_dbcoolsetup, "sysctl dBCool subtree setup")
    948   1.1  pgoyette {
    949   1.1  pgoyette 	sysctl_createv(NULL, 0, NULL, NULL,
    950   1.1  pgoyette 		       CTLFLAG_PERMANENT,
    951   1.1  pgoyette 		       CTLTYPE_NODE, "hw", NULL,
    952   1.1  pgoyette 		       NULL, 0, NULL, 0,
    953   1.1  pgoyette 		       CTL_HW, CTL_EOL);
    954   1.1  pgoyette }
    955   1.1  pgoyette 
    956   1.1  pgoyette static int
    957   1.2  pgoyette sysctl_dbcool_temp(SYSCTLFN_ARGS)
    958   1.1  pgoyette {
    959   1.1  pgoyette 	struct sysctlnode node;
    960   1.1  pgoyette 	struct dbcool_softc *sc;
    961   1.1  pgoyette 	int reg, error;
    962   1.1  pgoyette 	uint8_t chipreg;
    963   1.1  pgoyette 	uint8_t newreg;
    964   1.1  pgoyette 
    965   1.1  pgoyette 	node = *rnode;
    966   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
    967   1.2  pgoyette 	chipreg = node.sysctl_num & 0xff;
    968   1.1  pgoyette 
    969   1.1  pgoyette 	if (sc->sc_temp_offset) {
    970  1.13  christos 		reg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
    971   1.1  pgoyette 		reg -= sc->sc_temp_offset;
    972   1.1  pgoyette 	} else
    973  1.13  christos 		reg = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
    974   1.1  pgoyette 
    975   1.1  pgoyette 	node.sysctl_data = &reg;
    976   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    977   1.1  pgoyette 
    978   1.1  pgoyette 	if (error || newp == NULL)
    979   1.1  pgoyette 		return error;
    980   1.1  pgoyette 
    981   1.1  pgoyette 	/* We were asked to update the value - sanity check before writing */
    982   1.1  pgoyette 	if (*(int *)node.sysctl_data < -64 ||
    983   1.1  pgoyette 	    *(int *)node.sysctl_data > 127 + sc->sc_temp_offset)
    984   1.1  pgoyette 		return EINVAL;
    985   1.1  pgoyette 
    986   1.1  pgoyette 	newreg = *(int *)node.sysctl_data;
    987   1.1  pgoyette 	newreg += sc->sc_temp_offset;
    988  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
    989   1.1  pgoyette 	return 0;
    990   1.1  pgoyette }
    991   1.1  pgoyette 
    992   1.1  pgoyette static int
    993   1.2  pgoyette sysctl_adm1030_temp(SYSCTLFN_ARGS)
    994   1.1  pgoyette {
    995   1.1  pgoyette 	struct sysctlnode node;
    996   1.1  pgoyette 	struct dbcool_softc *sc;
    997   1.1  pgoyette 	int reg, error;
    998   1.1  pgoyette 	uint8_t chipreg, oldreg, newreg;
    999   1.1  pgoyette 
   1000   1.1  pgoyette 	node = *rnode;
   1001   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1002   1.2  pgoyette 	chipreg = node.sysctl_num & 0xff;
   1003   1.1  pgoyette 
   1004  1.13  christos 	oldreg = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
   1005   1.1  pgoyette 	reg = (oldreg >> 1) & ~0x03;
   1006   1.1  pgoyette 
   1007   1.1  pgoyette 	node.sysctl_data = &reg;
   1008   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1009   1.1  pgoyette 
   1010   1.1  pgoyette 	if (error || newp == NULL)
   1011   1.1  pgoyette 		return error;
   1012   1.1  pgoyette 
   1013   1.1  pgoyette 	/* We were asked to update the value - sanity check before writing */
   1014   1.1  pgoyette 	if (*(int *)node.sysctl_data < 0 || *(int *)node.sysctl_data > 127)
   1015   1.1  pgoyette 		return EINVAL;
   1016   1.1  pgoyette 
   1017   1.1  pgoyette 	newreg = *(int *)node.sysctl_data;
   1018   1.1  pgoyette 	newreg &= ~0x03;
   1019   1.1  pgoyette 	newreg <<= 1;
   1020   1.1  pgoyette 	newreg |= (oldreg & 0x07);
   1021  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1022   1.1  pgoyette 	return 0;
   1023   1.1  pgoyette }
   1024   1.1  pgoyette 
   1025   1.1  pgoyette static int
   1026   1.1  pgoyette sysctl_adm1030_trange(SYSCTLFN_ARGS)
   1027   1.1  pgoyette {
   1028   1.1  pgoyette 	struct sysctlnode node;
   1029   1.1  pgoyette 	struct dbcool_softc *sc;
   1030   1.1  pgoyette 	int reg, error, newval;
   1031   1.1  pgoyette 	uint8_t chipreg, oldreg, newreg;
   1032   1.1  pgoyette 
   1033   1.1  pgoyette 	node = *rnode;
   1034   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1035   1.2  pgoyette 	chipreg = node.sysctl_num & 0xff;
   1036   1.1  pgoyette 
   1037  1.13  christos 	oldreg = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
   1038   1.1  pgoyette 	reg = oldreg & 0x07;
   1039   1.1  pgoyette 
   1040   1.1  pgoyette 	node.sysctl_data = &reg;
   1041   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1042   1.1  pgoyette 
   1043   1.1  pgoyette 	if (error || newp == NULL)
   1044   1.1  pgoyette 		return error;
   1045   1.1  pgoyette 
   1046   1.1  pgoyette 	/* We were asked to update the value - sanity check before writing */
   1047   1.1  pgoyette 	newval = *(int *)node.sysctl_data;
   1048   1.1  pgoyette 
   1049   1.1  pgoyette 	if (newval == 5)
   1050   1.1  pgoyette 		newreg = 0;
   1051   1.1  pgoyette 	else if (newval == 10)
   1052   1.1  pgoyette 		newreg = 1;
   1053   1.1  pgoyette 	else if (newval == 20)
   1054   1.1  pgoyette 		newreg = 2;
   1055   1.1  pgoyette 	else if (newval == 40)
   1056   1.1  pgoyette 		newreg = 3;
   1057   1.1  pgoyette 	else if (newval == 80)
   1058   1.1  pgoyette 		newreg = 4;
   1059   1.1  pgoyette 	else
   1060   1.1  pgoyette 		return EINVAL;
   1061   1.1  pgoyette 
   1062   1.1  pgoyette 	newreg |= (oldreg & ~0x07);
   1063  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1064   1.1  pgoyette 	return 0;
   1065   1.1  pgoyette }
   1066   1.1  pgoyette 
   1067   1.1  pgoyette static int
   1068   1.1  pgoyette sysctl_dbcool_duty(SYSCTLFN_ARGS)
   1069   1.1  pgoyette {
   1070   1.1  pgoyette 	struct sysctlnode node;
   1071   1.1  pgoyette 	struct dbcool_softc *sc;
   1072   1.1  pgoyette 	int reg, error;
   1073   1.1  pgoyette 	uint8_t chipreg, oldreg, newreg;
   1074   1.1  pgoyette 
   1075   1.1  pgoyette 	node = *rnode;
   1076   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1077   1.2  pgoyette 	chipreg = node.sysctl_num & 0xff;
   1078   1.1  pgoyette 
   1079  1.13  christos 	oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
   1080   1.1  pgoyette 	reg = (uint32_t)oldreg;
   1081  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
   1082   1.1  pgoyette 		reg = ((reg & 0x0f) * 100) / 15;
   1083   1.1  pgoyette 	else
   1084   1.1  pgoyette 		reg = (reg * 100) / 255;
   1085   1.1  pgoyette 	node.sysctl_data = &reg;
   1086   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1087   1.1  pgoyette 
   1088   1.1  pgoyette 	if (error || newp == NULL)
   1089   1.1  pgoyette 		return error;
   1090   1.1  pgoyette 
   1091   1.1  pgoyette 	/* We were asked to update the value - sanity check before writing */
   1092   1.1  pgoyette 	if (*(int *)node.sysctl_data < 0 || *(int *)node.sysctl_data > 100)
   1093   1.1  pgoyette 		return EINVAL;
   1094   1.1  pgoyette 
   1095  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) {
   1096   1.1  pgoyette 		newreg = *(uint8_t *)(node.sysctl_data) * 15 / 100;
   1097   1.1  pgoyette 		newreg |= oldreg & 0xf0;
   1098   1.1  pgoyette 	} else
   1099   1.1  pgoyette 		newreg = *(uint8_t *)(node.sysctl_data) * 255 / 100;
   1100  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1101   1.1  pgoyette 	return 0;
   1102   1.1  pgoyette }
   1103   1.1  pgoyette 
   1104   1.1  pgoyette static int
   1105   1.1  pgoyette sysctl_dbcool_behavior(SYSCTLFN_ARGS)
   1106   1.1  pgoyette {
   1107   1.1  pgoyette 	struct sysctlnode node;
   1108   1.1  pgoyette 	struct dbcool_softc *sc;
   1109   1.1  pgoyette 	int i, reg, error;
   1110   1.1  pgoyette 	uint8_t chipreg, oldreg, newreg;
   1111   1.1  pgoyette 
   1112   1.1  pgoyette 	node = *rnode;
   1113   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1114   1.2  pgoyette 	chipreg = node.sysctl_num & 0xff;
   1115   1.1  pgoyette 
   1116  1.13  christos 	oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
   1117   1.2  pgoyette 
   1118  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) {
   1119  1.13  christos 		if ((sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_CFG2) & 1) == 0)
   1120   1.1  pgoyette 			reg = 4;
   1121   1.1  pgoyette 		else if ((oldreg & 0x80) == 0)
   1122   1.1  pgoyette 			reg = 7;
   1123   1.1  pgoyette 		else if ((oldreg & 0x60) == 0)
   1124   1.1  pgoyette 			reg = 4;
   1125   1.1  pgoyette 		else
   1126   1.1  pgoyette 			reg = 6;
   1127   1.1  pgoyette 	} else
   1128   1.1  pgoyette 		reg = (oldreg >> 5) & 0x07;
   1129   1.1  pgoyette 
   1130   1.1  pgoyette 	strlcpy(dbcool_cur_behav, behavior[reg], sizeof(dbcool_cur_behav));
   1131   1.1  pgoyette 	node.sysctl_data = dbcool_cur_behav;
   1132   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1133   1.1  pgoyette 
   1134   1.1  pgoyette 	if (error || newp == NULL)
   1135   1.1  pgoyette 		return error;
   1136   1.1  pgoyette 
   1137   1.1  pgoyette 	/* We were asked to update the value - convert string to value */
   1138   1.1  pgoyette 	newreg = __arraycount(behavior);
   1139   1.1  pgoyette 	for (i = 0; i < __arraycount(behavior); i++)
   1140   1.1  pgoyette 		if (strcmp(node.sysctl_data, behavior[i]) == 0)
   1141   1.1  pgoyette 			break;
   1142   1.1  pgoyette 	if (i >= __arraycount(behavior))
   1143   1.1  pgoyette 		return EINVAL;
   1144   1.1  pgoyette 
   1145  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) {
   1146   1.1  pgoyette 		/*
   1147   1.1  pgoyette 		 * ADM1030 splits fan controller behavior across two
   1148   1.1  pgoyette 		 * registers.  We also do not support Auto-Filter mode
   1149   1.1  pgoyette 		 * nor do we support Manual-RPM-feedback.
   1150   1.1  pgoyette 		 */
   1151   1.1  pgoyette 		if (newreg == 4) {
   1152  1.13  christos 			oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_CFG2);
   1153   1.1  pgoyette 			oldreg &= ~0x01;
   1154  1.13  christos 			sc->sc_dc.dc_writereg(&sc->sc_dc, DBCOOL_ADM1030_CFG2, oldreg);
   1155   1.1  pgoyette 		} else {
   1156   1.1  pgoyette 			if (newreg == 0)
   1157   1.1  pgoyette 				newreg = 4;
   1158   1.1  pgoyette 			else if (newreg == 6)
   1159   1.1  pgoyette 				newreg = 7;
   1160   1.1  pgoyette 			else if (newreg == 7)
   1161   1.1  pgoyette 				newreg = 0;
   1162   1.1  pgoyette 			else
   1163   1.1  pgoyette 				return EINVAL;
   1164   1.1  pgoyette 			newreg <<= 5;
   1165   1.1  pgoyette 			newreg |= (oldreg & 0x1f);
   1166  1.13  christos 			sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1167  1.13  christos 			oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_CFG2) | 1;
   1168  1.13  christos 			sc->sc_dc.dc_writereg(&sc->sc_dc, DBCOOL_ADM1030_CFG2, oldreg);
   1169   1.1  pgoyette 		}
   1170   1.1  pgoyette 	} else {
   1171  1.13  christos 		newreg = (sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg) & 0x1f) | (i << 5);
   1172  1.13  christos 		sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1173   1.1  pgoyette 	}
   1174   1.1  pgoyette 	return 0;
   1175   1.1  pgoyette }
   1176   1.1  pgoyette 
   1177   1.1  pgoyette static int
   1178   1.2  pgoyette sysctl_dbcool_slope(SYSCTLFN_ARGS)
   1179   1.1  pgoyette {
   1180   1.1  pgoyette 	struct sysctlnode node;
   1181   1.1  pgoyette 	struct dbcool_softc *sc;
   1182   1.1  pgoyette 	int reg, error;
   1183   1.1  pgoyette 	uint8_t chipreg;
   1184   1.1  pgoyette 	uint8_t newreg;
   1185   1.1  pgoyette 
   1186   1.1  pgoyette 	node = *rnode;
   1187   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1188   1.2  pgoyette 	chipreg = node.sysctl_num & 0xff;
   1189   1.1  pgoyette 
   1190  1.13  christos 	reg = (sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg) >> 4) & 0x0f;
   1191   1.1  pgoyette 	node.sysctl_data = &reg;
   1192   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1193   1.1  pgoyette 
   1194   1.1  pgoyette 	if (error || newp == NULL)
   1195   1.1  pgoyette 		return error;
   1196   1.1  pgoyette 
   1197   1.1  pgoyette 	/* We were asked to update the value - sanity check before writing */
   1198   1.1  pgoyette 	if (*(int *)node.sysctl_data < 0 || *(int *)node.sysctl_data > 0x0f)
   1199   1.1  pgoyette 		return EINVAL;
   1200   1.1  pgoyette 
   1201  1.13  christos 	newreg = (sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg) & 0x0f) |
   1202   1.1  pgoyette 		  (*(int *)node.sysctl_data << 4);
   1203  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1204   1.1  pgoyette 	return 0;
   1205   1.1  pgoyette }
   1206   1.1  pgoyette 
   1207   1.1  pgoyette static int
   1208   1.1  pgoyette sysctl_dbcool_volt_limit(SYSCTLFN_ARGS)
   1209   1.1  pgoyette {
   1210   1.1  pgoyette 	struct sysctlnode node;
   1211   1.1  pgoyette 	struct dbcool_softc *sc;
   1212   1.1  pgoyette 	int reg, error;
   1213   1.2  pgoyette 	int nom, sensor_index;
   1214   1.2  pgoyette 	int64_t val, newval;
   1215   1.1  pgoyette 	uint8_t chipreg, newreg;
   1216   1.1  pgoyette 
   1217   1.1  pgoyette 	node = *rnode;
   1218   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1219   1.2  pgoyette 	chipreg = node.sysctl_num & 0xff;
   1220   1.1  pgoyette 
   1221   1.1  pgoyette 	/*
   1222   1.2  pgoyette 	 * Retrieve the nominal value for the voltage sensor
   1223   1.1  pgoyette 	 */
   1224   1.2  pgoyette 	sensor_index = (node.sysctl_num >> 8 ) & 0xff;
   1225  1.13  christos 	nom = nominal_voltages[sc->sc_dc.dc_chip->table[sensor_index].nom_volt_index];
   1226   1.2  pgoyette 	if (nom < 0)
   1227   1.2  pgoyette 		nom = dbcool_supply_voltage(sc);
   1228   1.1  pgoyette 
   1229   1.2  pgoyette 	/*
   1230   1.2  pgoyette 	 * Use int64_t for calculation to avoid overflow
   1231   1.2  pgoyette 	 */
   1232  1.13  christos 	val =  sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
   1233   1.2  pgoyette 	val *= nom;
   1234   1.2  pgoyette 	val /= 0xc0;	/* values are scaled so 0xc0 == nominal voltage */
   1235   1.2  pgoyette 	reg = val;
   1236   1.1  pgoyette 	node.sysctl_data = &reg;
   1237   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1238   1.1  pgoyette 
   1239   1.1  pgoyette 	if (error || newp == NULL)
   1240   1.1  pgoyette 		return error;
   1241   1.1  pgoyette 
   1242   1.1  pgoyette 	/*
   1243   1.1  pgoyette 	 * We were asked to update the value, so scale it and sanity
   1244   1.1  pgoyette 	 * check before writing
   1245   1.1  pgoyette 	 */
   1246   1.1  pgoyette 	if (nom == 0)
   1247   1.1  pgoyette 		return EINVAL;
   1248   1.1  pgoyette 	newval =  *(int *)node.sysctl_data;
   1249   1.1  pgoyette 	newval *= 0xc0;
   1250   1.1  pgoyette 	newval /= nom;
   1251   1.1  pgoyette 	if (newval < 0 || newval > 0xff)
   1252   1.1  pgoyette 		return EINVAL;
   1253   1.1  pgoyette 
   1254   1.1  pgoyette 	newreg = newval;
   1255  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1256   1.1  pgoyette 	return 0;
   1257   1.1  pgoyette }
   1258   1.1  pgoyette 
   1259   1.1  pgoyette static int
   1260   1.1  pgoyette sysctl_dbcool_temp_limit(SYSCTLFN_ARGS)
   1261   1.1  pgoyette {
   1262   1.1  pgoyette 	struct sysctlnode node;
   1263   1.1  pgoyette 	struct dbcool_softc *sc;
   1264   1.1  pgoyette 	int reg, error, newtemp;
   1265   1.1  pgoyette 	uint8_t chipreg;
   1266   1.1  pgoyette 
   1267   1.1  pgoyette 	node = *rnode;
   1268   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1269   1.2  pgoyette 	chipreg = node.sysctl_num & 0xff;
   1270   1.1  pgoyette 
   1271   1.1  pgoyette 	/* If using offset mode, adjust, else treat as signed */
   1272   1.1  pgoyette 	if (sc->sc_temp_offset) {
   1273  1.13  christos 		reg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
   1274   1.1  pgoyette 		reg -= sc->sc_temp_offset;
   1275   1.1  pgoyette 	 } else
   1276  1.13  christos 		reg = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
   1277   1.1  pgoyette 
   1278   1.1  pgoyette 	node.sysctl_data = &reg;
   1279   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1280   1.1  pgoyette 
   1281   1.1  pgoyette 	if (error || newp == NULL)
   1282   1.1  pgoyette 		return error;
   1283   1.1  pgoyette 
   1284   1.1  pgoyette 	/* We were asked to update the value - sanity check before writing */
   1285   1.1  pgoyette 	newtemp = *(int *)node.sysctl_data + sc->sc_temp_offset;
   1286   1.1  pgoyette 	if (newtemp < 0 || newtemp > 0xff)
   1287   1.1  pgoyette 		return EINVAL;
   1288   1.1  pgoyette 
   1289  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newtemp);
   1290   1.1  pgoyette 	return 0;
   1291   1.1  pgoyette }
   1292   1.1  pgoyette 
   1293   1.1  pgoyette static int
   1294   1.1  pgoyette sysctl_dbcool_fan_limit(SYSCTLFN_ARGS)
   1295   1.1  pgoyette {
   1296   1.1  pgoyette 	struct sysctlnode node;
   1297   1.1  pgoyette 	struct dbcool_softc *sc;
   1298   1.1  pgoyette 	int reg, error, newrpm, dividend;
   1299   1.1  pgoyette 	uint8_t chipreg;
   1300   1.1  pgoyette 	uint8_t newreg;
   1301   1.1  pgoyette 
   1302   1.1  pgoyette 	node = *rnode;
   1303   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1304   1.2  pgoyette 	chipreg = node.sysctl_num & 0xff;
   1305   1.1  pgoyette 
   1306   1.1  pgoyette 	/* retrieve two-byte limit */
   1307   1.1  pgoyette 	reg = dbcool_read_rpm(sc, chipreg);
   1308   1.1  pgoyette 
   1309   1.1  pgoyette 	node.sysctl_data = &reg;
   1310   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1311   1.1  pgoyette 
   1312   1.1  pgoyette 	if (error || newp == NULL)
   1313   1.1  pgoyette 		return error;
   1314   1.1  pgoyette 
   1315   1.1  pgoyette 	/*
   1316   1.1  pgoyette 	 * We were asked to update the value.  Calculate the two-byte
   1317   1.1  pgoyette 	 * limit and validate it.  Due to the way fan RPM is calculated,
   1318   1.1  pgoyette 	 * the new value must be at least 83 RPM (331 RPM for ADM1030)!
   1319   1.1  pgoyette 	 * Allow a value of -1 or 0 to indicate no limit.
   1320   1.1  pgoyette 	 */
   1321   1.1  pgoyette 	newrpm = *(int *)node.sysctl_data;
   1322   1.1  pgoyette 	if (newrpm == 0 || newrpm == -1)
   1323   1.1  pgoyette 		newrpm = 0xffff;
   1324   1.1  pgoyette 	else {
   1325  1.13  christos 		if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
   1326   1.1  pgoyette 			dividend = 11250 * 60;
   1327   1.1  pgoyette 		else
   1328   1.1  pgoyette 			dividend = 90000 * 60;
   1329   1.1  pgoyette 		newrpm = dividend / newrpm;
   1330   1.1  pgoyette 		if (newrpm & ~0xffff)
   1331   1.1  pgoyette 			return EINVAL;
   1332   1.1  pgoyette 	}
   1333   1.1  pgoyette 
   1334   1.1  pgoyette 	/* Update the on-chip registers with new value */
   1335   1.1  pgoyette 	newreg = newrpm & 0xff;
   1336  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1337   1.1  pgoyette 	newreg = (newrpm >> 8) & 0xff;
   1338  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg + 1, newreg);
   1339   1.1  pgoyette 	return 0;
   1340   1.1  pgoyette }
   1341   1.1  pgoyette 
   1342   1.1  pgoyette static int
   1343   1.1  pgoyette sysctl_dbcool_vid(SYSCTLFN_ARGS)
   1344   1.1  pgoyette {
   1345   1.1  pgoyette 	struct sysctlnode node;
   1346   1.1  pgoyette 	struct dbcool_softc *sc;
   1347   1.1  pgoyette 	int reg, error;
   1348   1.1  pgoyette 	uint8_t chipreg, newreg;
   1349   1.1  pgoyette 
   1350   1.1  pgoyette 	node = *rnode;
   1351   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1352   1.1  pgoyette 	chipreg = node.sysctl_num;
   1353   1.1  pgoyette 
   1354   1.1  pgoyette 	/* retrieve 5- or 6-bit value */
   1355  1.13  christos 	newreg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
   1356  1.13  christos 	if ((sc->sc_dc.dc_chip->flags & DBCFLAG_HAS_VID_SEL) &&
   1357   1.1  pgoyette 	    (reg & 0x80))
   1358   1.1  pgoyette 		reg = newreg & 0x3f;
   1359   1.1  pgoyette 	else
   1360   1.1  pgoyette 		reg = newreg & 0x1f;
   1361   1.1  pgoyette 
   1362   1.1  pgoyette 	node.sysctl_data = &reg;
   1363   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1364   1.1  pgoyette 
   1365   1.1  pgoyette 	if (error == 0 && newp != NULL)
   1366   1.1  pgoyette 		error = EINVAL;
   1367   1.1  pgoyette 
   1368   1.1  pgoyette 	return error;
   1369   1.1  pgoyette }
   1370   1.1  pgoyette 
   1371   1.1  pgoyette static int
   1372   1.1  pgoyette sysctl_dbcool_thyst(SYSCTLFN_ARGS)
   1373   1.1  pgoyette {
   1374   1.1  pgoyette 	struct sysctlnode node;
   1375   1.1  pgoyette 	struct dbcool_softc *sc;
   1376   1.1  pgoyette 	int reg, error;
   1377   1.1  pgoyette 	uint8_t chipreg;
   1378   1.1  pgoyette 	uint8_t newreg, newhyst;
   1379   1.1  pgoyette 
   1380   1.1  pgoyette 	node = *rnode;
   1381   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1382   1.1  pgoyette 	chipreg = node.sysctl_num & 0x7f;
   1383   1.1  pgoyette 
   1384   1.1  pgoyette 	/* retrieve 4-bit value */
   1385  1.13  christos 	newreg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
   1386   1.1  pgoyette 	if ((node.sysctl_num & 0x80) == 0)
   1387   1.1  pgoyette 		reg = newreg >> 4;
   1388   1.1  pgoyette 	else
   1389   1.1  pgoyette 		reg = newreg;
   1390   1.1  pgoyette 	reg = reg & 0x0f;
   1391   1.1  pgoyette 
   1392   1.1  pgoyette 	node.sysctl_data = &reg;
   1393   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1394   1.1  pgoyette 
   1395   1.1  pgoyette 	if (error || newp == NULL)
   1396   1.1  pgoyette 		return error;
   1397   1.1  pgoyette 
   1398   1.1  pgoyette 	/* We were asked to update the value - sanity check before writing */
   1399   1.1  pgoyette 	newhyst = *(int *)node.sysctl_data;
   1400   1.1  pgoyette 	if (newhyst > 0x0f)
   1401   1.1  pgoyette 		return EINVAL;
   1402   1.1  pgoyette 
   1403   1.1  pgoyette 	/* Insert new value into field and update register */
   1404   1.1  pgoyette 	if ((node.sysctl_num & 0x80) == 0) {
   1405   1.1  pgoyette 		newreg &= 0x0f;
   1406   1.1  pgoyette 		newreg |= (newhyst << 4);
   1407   1.1  pgoyette 	} else {
   1408   1.1  pgoyette 		newreg &= 0xf0;
   1409   1.1  pgoyette 		newreg |= newhyst;
   1410   1.1  pgoyette 	}
   1411  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1412   1.1  pgoyette 	return 0;
   1413   1.1  pgoyette }
   1414   1.1  pgoyette 
   1415   1.1  pgoyette #ifdef DBCOOL_DEBUG
   1416   1.1  pgoyette 
   1417   1.1  pgoyette /*
   1418   1.1  pgoyette  * These routines can be used for debugging.  reg_select is used to
   1419   1.1  pgoyette  * select any arbitrary register in the device.  reg_access is used
   1420   1.1  pgoyette  * to read (and optionally update) the selected register.
   1421   1.1  pgoyette  *
   1422   1.1  pgoyette  * No attempt is made to validate the data passed.  If you use these
   1423   1.1  pgoyette  * routines, you are assumed to know what you're doing!
   1424   1.1  pgoyette  *
   1425   1.1  pgoyette  * Caveat user
   1426   1.1  pgoyette  */
   1427   1.1  pgoyette static int
   1428   1.1  pgoyette sysctl_dbcool_reg_select(SYSCTLFN_ARGS)
   1429   1.1  pgoyette {
   1430   1.1  pgoyette 	struct sysctlnode node;
   1431   1.1  pgoyette 	struct dbcool_softc *sc;
   1432   1.1  pgoyette 	int reg, error;
   1433   1.1  pgoyette 
   1434   1.1  pgoyette 	node = *rnode;
   1435   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1436   1.1  pgoyette 
   1437   1.1  pgoyette 	reg = sc->sc_user_reg;
   1438   1.1  pgoyette 	node.sysctl_data = &reg;
   1439   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1440   1.1  pgoyette 
   1441   1.1  pgoyette 	if (error || newp == NULL)
   1442   1.1  pgoyette 		return error;
   1443   1.1  pgoyette 
   1444   1.1  pgoyette 	sc->sc_user_reg = *(int *)node.sysctl_data;
   1445   1.1  pgoyette 	return 0;
   1446   1.1  pgoyette }
   1447   1.1  pgoyette 
   1448   1.1  pgoyette static int
   1449   1.1  pgoyette sysctl_dbcool_reg_access(SYSCTLFN_ARGS)
   1450   1.1  pgoyette {
   1451   1.1  pgoyette 	struct sysctlnode node;
   1452   1.1  pgoyette 	struct dbcool_softc *sc;
   1453   1.1  pgoyette 	int reg, error;
   1454   1.1  pgoyette 	uint8_t chipreg;
   1455   1.1  pgoyette 	uint8_t newreg;
   1456   1.1  pgoyette 
   1457   1.1  pgoyette 	node = *rnode;
   1458   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1459   1.1  pgoyette 	chipreg = sc->sc_user_reg;
   1460   1.1  pgoyette 
   1461  1.13  christos 	reg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
   1462   1.1  pgoyette 	node.sysctl_data = &reg;
   1463   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1464   1.1  pgoyette 
   1465   1.1  pgoyette 	if (error || newp == NULL)
   1466   1.1  pgoyette 		return error;
   1467   1.1  pgoyette 
   1468   1.1  pgoyette 	newreg = *(int *)node.sysctl_data;
   1469  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1470   1.1  pgoyette 	return 0;
   1471   1.1  pgoyette }
   1472   1.1  pgoyette #endif /* DBCOOL_DEBUG */
   1473   1.1  pgoyette 
   1474   1.1  pgoyette /*
   1475   1.2  pgoyette  * Encode an index number and register number for use as a sysctl_num
   1476   1.2  pgoyette  * so we can select the correct device register later.
   1477   1.1  pgoyette  */
   1478   1.2  pgoyette #define	DBC_PWM_SYSCTL(seq, reg)	((seq << 8) | reg)
   1479   1.1  pgoyette 
   1480   1.1  pgoyette void
   1481   1.1  pgoyette dbcool_setup(device_t self)
   1482   1.1  pgoyette {
   1483   1.1  pgoyette 	struct dbcool_softc *sc = device_private(self);
   1484   1.1  pgoyette 	const struct sysctlnode *me = NULL;
   1485   1.1  pgoyette 	struct sysctlnode *node = NULL;
   1486   1.1  pgoyette 	uint8_t cfg_val, cfg_reg;
   1487   1.2  pgoyette 	int ro_flag, rw_flag, ret, error;
   1488   1.1  pgoyette 
   1489   1.1  pgoyette 	/*
   1490   1.1  pgoyette 	 * Some chips are capable of reporting an extended temperature range
   1491   1.1  pgoyette 	 * by default.  On these models, config register 5 bit 0 can be set
   1492   1.1  pgoyette 	 * to 1 for compatability with other chips that report 2s complement.
   1493   1.1  pgoyette 	 */
   1494  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) {
   1495  1.13  christos 		if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADT7466_CONFIG1) & 0x80)
   1496   1.1  pgoyette 			sc->sc_temp_offset = 64;
   1497   1.1  pgoyette 		else
   1498   1.1  pgoyette 			sc->sc_temp_offset = 0;
   1499  1.13  christos 	} else if (sc->sc_dc.dc_chip->flags & DBCFLAG_TEMPOFFSET) {
   1500  1.13  christos 		if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_CONFIG5_REG) &
   1501   1.1  pgoyette 			    DBCOOL_CFG5_TWOSCOMP)
   1502   1.1  pgoyette 			sc->sc_temp_offset = 0;
   1503   1.1  pgoyette 		else
   1504   1.1  pgoyette 			sc->sc_temp_offset = 64;
   1505   1.1  pgoyette 	} else
   1506   1.1  pgoyette 		sc->sc_temp_offset = 0;
   1507   1.1  pgoyette 
   1508   1.2  pgoyette 	/* Determine Vcc for this chip */
   1509   1.2  pgoyette 	sc->sc_supply_voltage = dbcool_supply_voltage(sc);
   1510   1.2  pgoyette 
   1511   1.1  pgoyette 	sc->sc_sme = sysmon_envsys_create();
   1512   1.1  pgoyette 
   1513   1.2  pgoyette 	ro_flag = dbcool_islocked(sc)?CTLFLAG_READONLY:CTLFLAG_READWRITE;
   1514   1.2  pgoyette 	ro_flag |= CTLFLAG_OWNDESC;
   1515   1.2  pgoyette 	rw_flag = CTLFLAG_READWRITE | CTLFLAG_OWNDESC;
   1516   1.1  pgoyette 	ret = sysctl_createv(NULL, 0, NULL, &me,
   1517   1.2  pgoyette 	       CTLFLAG_READWRITE,
   1518   1.1  pgoyette 	       CTLTYPE_NODE, device_xname(self), NULL,
   1519   1.1  pgoyette 	       NULL, 0, NULL, 0,
   1520   1.1  pgoyette 	       CTL_HW, CTL_CREATE, CTL_EOL);
   1521  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_HAS_VID) {
   1522   1.1  pgoyette 		ret = sysctl_createv(NULL, 0, NULL,
   1523   1.1  pgoyette 			(const struct sysctlnode **)&node,
   1524   1.2  pgoyette 			CTLFLAG_READONLY, CTLTYPE_INT, "CPU_VID_bits", NULL,
   1525   1.1  pgoyette 			sysctl_dbcool_vid,
   1526   1.1  pgoyette 			0, sc, sizeof(int),
   1527   1.1  pgoyette 			CTL_HW, me->sysctl_num, DBCOOL_VID_REG, CTL_EOL);
   1528   1.1  pgoyette 		if (node != NULL)
   1529   1.1  pgoyette 			node->sysctl_data = sc;
   1530   1.1  pgoyette 	}
   1531   1.1  pgoyette 
   1532   1.1  pgoyette #ifdef DBCOOL_DEBUG
   1533   1.1  pgoyette 	ret = sysctl_createv(NULL, 0, NULL,
   1534   1.1  pgoyette 		(const struct sysctlnode **)&node,
   1535   1.1  pgoyette 		CTLFLAG_READWRITE, CTLTYPE_INT, "reg_select", NULL,
   1536   1.1  pgoyette 		sysctl_dbcool_reg_select,
   1537   1.1  pgoyette 		0, sc, sizeof(int),
   1538   1.1  pgoyette 		CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL);
   1539   1.1  pgoyette 	if (node != NULL)
   1540   1.1  pgoyette 		node->sysctl_data = sc;
   1541   1.1  pgoyette 
   1542   1.1  pgoyette 	ret = sysctl_createv(NULL, 0, NULL,
   1543   1.1  pgoyette 		(const struct sysctlnode **)&node,
   1544   1.1  pgoyette 		CTLFLAG_READWRITE, CTLTYPE_INT, "reg_access", NULL,
   1545   1.1  pgoyette 		sysctl_dbcool_reg_access,
   1546   1.1  pgoyette 		0, sc, sizeof(int),
   1547   1.1  pgoyette 		CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL);
   1548   1.1  pgoyette 	if (node != NULL)
   1549   1.1  pgoyette 		node->sysctl_data = sc;
   1550   1.1  pgoyette #endif /* DBCOOL_DEBUG */
   1551   1.1  pgoyette 
   1552   1.2  pgoyette 	/* Create the sensors for this device */
   1553   1.2  pgoyette 	if (dbcool_setup_sensors(sc, me, rw_flag, ro_flag))
   1554   1.2  pgoyette 		goto out;
   1555   1.2  pgoyette 
   1556   1.2  pgoyette 	/* If supported, create sysctl tree for fan PWM controllers */
   1557  1.13  christos 	if (sc->sc_dc.dc_chip->power != NULL)
   1558   1.2  pgoyette 		dbcool_setup_controllers(sc, me, rw_flag, ro_flag);
   1559   1.2  pgoyette 
   1560   1.2  pgoyette 	/*
   1561   1.2  pgoyette 	 * Read and rewrite config register to activate device
   1562   1.2  pgoyette 	 */
   1563  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
   1564   1.2  pgoyette 		cfg_reg = DBCOOL_ADM1030_CFG1;
   1565  1.13  christos 	else if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466)
   1566   1.2  pgoyette 		cfg_reg = DBCOOL_ADT7466_CONFIG1;
   1567   1.2  pgoyette 	else
   1568   1.2  pgoyette 		cfg_reg = DBCOOL_CONFIG1_REG;
   1569  1.13  christos 	cfg_val = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_CONFIG1_REG);
   1570   1.2  pgoyette 	if ((cfg_val & DBCOOL_CFG1_START) == 0) {
   1571   1.2  pgoyette 		cfg_val |= DBCOOL_CFG1_START;
   1572  1.13  christos 		sc->sc_dc.dc_writereg(&sc->sc_dc, cfg_reg, cfg_val);
   1573   1.2  pgoyette 	}
   1574   1.2  pgoyette 	if (dbcool_islocked(sc))
   1575   1.2  pgoyette 		aprint_normal_dev(self, "configuration locked\n");
   1576   1.2  pgoyette 
   1577   1.2  pgoyette 	sc->sc_sme->sme_name = device_xname(self);
   1578   1.2  pgoyette 	sc->sc_sme->sme_cookie = sc;
   1579   1.2  pgoyette 	sc->sc_sme->sme_refresh = dbcool_refresh;
   1580   1.2  pgoyette 
   1581   1.2  pgoyette 	if ((error = sysmon_envsys_register(sc->sc_sme)) != 0) {
   1582   1.2  pgoyette 		aprint_error_dev(self,
   1583   1.2  pgoyette 		    "unable to register with sysmon (%d)\n", error);
   1584   1.2  pgoyette 		goto out;
   1585   1.2  pgoyette 	}
   1586   1.2  pgoyette 
   1587   1.2  pgoyette 	return;
   1588   1.2  pgoyette 
   1589   1.2  pgoyette out:
   1590   1.2  pgoyette 	sysmon_envsys_destroy(sc->sc_sme);
   1591   1.2  pgoyette }
   1592   1.2  pgoyette 
   1593   1.2  pgoyette static int
   1594   1.2  pgoyette dbcool_setup_sensors(struct dbcool_softc *sc, const struct sysctlnode *me,
   1595   1.2  pgoyette 		     int rw_flag, int ro_flag)
   1596   1.2  pgoyette {
   1597   1.2  pgoyette 	int i, j, ret;
   1598   1.2  pgoyette 	int error = 0;
   1599   1.2  pgoyette 	uint8_t	sysctl_reg;
   1600   1.2  pgoyette 	struct sysctlnode *node = NULL;
   1601   1.2  pgoyette 	int sysctl_index, sysctl_num;
   1602   1.2  pgoyette 	char name[SYSCTL_NAMELEN];
   1603   1.2  pgoyette 
   1604  1.13  christos 	for (i=0; sc->sc_dc.dc_chip->table[i].type != DBC_EOF; i++) {
   1605   1.1  pgoyette 		if (i >= DBCOOL_MAXSENSORS &&
   1606  1.13  christos 		    sc->sc_dc.dc_chip->table[i].type != DBC_CTL) {
   1607   1.2  pgoyette 			aprint_normal_dev(sc->sc_dev, "chip table too big!\n");
   1608   1.1  pgoyette 			break;
   1609   1.1  pgoyette 		}
   1610  1.13  christos 		switch (sc->sc_dc.dc_chip->table[i].type) {
   1611   1.1  pgoyette 		case DBC_TEMP:
   1612   1.1  pgoyette 			sc->sc_sensor[i].units = ENVSYS_STEMP;
   1613   1.2  pgoyette 			error = dbcool_attach_sensor(sc, me, i,
   1614   1.2  pgoyette 					sysctl_dbcool_temp_limit);
   1615   1.1  pgoyette 			break;
   1616   1.1  pgoyette 		case DBC_VOLT:
   1617   1.1  pgoyette 			sc->sc_sensor[i].units = ENVSYS_SVOLTS_DC;
   1618   1.2  pgoyette 			error = dbcool_attach_sensor(sc, me, i,
   1619   1.2  pgoyette 					sysctl_dbcool_volt_limit);
   1620   1.1  pgoyette 			break;
   1621   1.1  pgoyette 		case DBC_FAN:
   1622   1.1  pgoyette 			sc->sc_sensor[i].units = ENVSYS_SFANRPM;
   1623   1.2  pgoyette 			error = dbcool_attach_sensor(sc, me, i,
   1624   1.2  pgoyette 					sysctl_dbcool_fan_limit);
   1625   1.1  pgoyette 			break;
   1626   1.1  pgoyette 		case DBC_CTL:
   1627   1.1  pgoyette 			/*
   1628   1.1  pgoyette 			 * Search for the corresponding temp sensor
   1629   1.1  pgoyette 			 * (temp sensors need to be created first!)
   1630   1.1  pgoyette 			 */
   1631   1.1  pgoyette 			sysctl_num = -1;
   1632   1.1  pgoyette 			for (j = 0; j < i; j++) {
   1633   1.1  pgoyette 				if (j > DBCOOL_MAXSENSORS ||
   1634  1.13  christos 				    sc->sc_dc.dc_chip->table[j].type != DBC_TEMP)
   1635   1.1  pgoyette 					continue;
   1636  1.13  christos 				if (sc->sc_dc.dc_chip->table[j].name_index ==
   1637  1.13  christos 				    sc->sc_dc.dc_chip->table[i].name_index) {
   1638   1.2  pgoyette 					sysctl_num = sc->sc_sysctl_num[j];
   1639   1.2  pgoyette 					break;
   1640   1.2  pgoyette 				}
   1641   1.1  pgoyette 			}
   1642   1.1  pgoyette 			if (sysctl_num == -1)
   1643   1.1  pgoyette 				break;
   1644  1.13  christos 			sysctl_index = sc->sc_dc.dc_chip->table[i].sysctl_index;
   1645  1.13  christos 			sysctl_reg = sc->sc_dc.dc_chip->table[i].reg.val_reg;
   1646   1.1  pgoyette 			strlcpy(name, dbc_sysctl_table[sysctl_index].name,
   1647   1.1  pgoyette 			    sizeof(name));
   1648   1.1  pgoyette 			ret = sysctl_createv(NULL, 0, NULL,
   1649   1.1  pgoyette 				(const struct sysctlnode **)&node,
   1650   1.2  pgoyette 				dbc_sysctl_table[sysctl_index].lockable?
   1651   1.2  pgoyette 					ro_flag:rw_flag,
   1652   1.2  pgoyette 				CTLTYPE_INT, name,
   1653   1.1  pgoyette 				dbc_sysctl_table[sysctl_index].desc,
   1654   1.1  pgoyette 				dbc_sysctl_table[sysctl_index].helper,
   1655   1.1  pgoyette 				0, sc, sizeof(int),
   1656   1.1  pgoyette 				CTL_HW, me->sysctl_num, sysctl_num,
   1657   1.2  pgoyette 				DBC_PWM_SYSCTL(i, sysctl_reg), CTL_EOL);
   1658   1.1  pgoyette 			if (node != NULL)
   1659   1.1  pgoyette 				node->sysctl_data = sc;
   1660   1.1  pgoyette 			break;
   1661   1.1  pgoyette 		default:
   1662   1.2  pgoyette 			aprint_error_dev(sc->sc_dev,
   1663   1.2  pgoyette 				"sensor_table index %d has bad type %d\n",
   1664  1.13  christos 				i, sc->sc_dc.dc_chip->table[i].type);
   1665   1.1  pgoyette 			break;
   1666   1.1  pgoyette 		}
   1667   1.2  pgoyette 		if (error)
   1668   1.2  pgoyette 			break;
   1669   1.2  pgoyette 	}
   1670   1.2  pgoyette 	return error;
   1671   1.2  pgoyette }
   1672   1.1  pgoyette 
   1673   1.2  pgoyette static int
   1674   1.2  pgoyette dbcool_attach_sensor(struct dbcool_softc *sc, const struct sysctlnode *me,
   1675   1.2  pgoyette 		     int idx, int (*helper)(SYSCTLFN_PROTO))
   1676   1.2  pgoyette {
   1677   1.2  pgoyette 	struct sysctlnode *node = NULL;
   1678   1.2  pgoyette 	const struct sysctlnode *me2 = NULL;
   1679   1.2  pgoyette 	uint8_t sysctl_reg;
   1680   1.2  pgoyette 	int name_index;
   1681   1.2  pgoyette 	int ret;
   1682   1.2  pgoyette 	int error = 0;
   1683   1.2  pgoyette 
   1684  1.13  christos 	name_index = sc->sc_dc.dc_chip->table[idx].name_index;
   1685   1.2  pgoyette 	strlcpy(sc->sc_sensor[idx].desc, dbc_sensor_names[name_index],
   1686   1.2  pgoyette 		sizeof(sc->sc_sensor[idx].desc));
   1687  1.13  christos 	sc->sc_regs[idx] = &sc->sc_dc.dc_chip->table[idx].reg;
   1688  1.13  christos 	sc->sc_nom_volt[idx] = sc->sc_dc.dc_chip->table[idx].nom_volt_index;
   1689   1.2  pgoyette 
   1690  1.12  pgoyette 	sc->sc_sensor[idx].flags |= ENVSYS_FMONLIMITS;
   1691   1.2  pgoyette 
   1692   1.2  pgoyette 	error = sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[idx]);
   1693   1.2  pgoyette 	if (error)
   1694   1.2  pgoyette 		return error;
   1695   1.2  pgoyette 
   1696   1.2  pgoyette 	/*
   1697   1.2  pgoyette 	 * create sysctl node for the sensor, and the nodes for
   1698   1.2  pgoyette 	 * the sensor's high and low limit values
   1699   1.2  pgoyette 	 */
   1700   1.2  pgoyette 	ret = sysctl_createv(NULL, 0, NULL, &me2, CTLFLAG_READWRITE,
   1701   1.2  pgoyette 			CTLTYPE_NODE, sc->sc_sensor[idx].desc, NULL,
   1702   1.2  pgoyette 			NULL, 0, NULL, 0,
   1703   1.2  pgoyette 			CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL);
   1704   1.2  pgoyette 	if (me2 == NULL)
   1705   1.2  pgoyette 		return 0;
   1706   1.2  pgoyette 
   1707   1.2  pgoyette 	sc->sc_sysctl_num[idx] = me2->sysctl_num;
   1708   1.1  pgoyette 
   1709   1.2  pgoyette 	/* create sysctl node for the low limit */
   1710   1.2  pgoyette 	sysctl_reg = sc->sc_regs[idx]->lo_lim_reg;
   1711   1.2  pgoyette 	ret = sysctl_createv(NULL, 0, NULL,
   1712   1.2  pgoyette 			(const struct sysctlnode **)&node,
   1713   1.2  pgoyette 			CTLFLAG_READWRITE,
   1714   1.2  pgoyette 			CTLTYPE_INT, "low_lim", NULL, helper, 0, sc, 0,
   1715   1.2  pgoyette 			CTL_HW, me->sysctl_num, me2->sysctl_num,
   1716   1.2  pgoyette 			DBC_PWM_SYSCTL(idx, sysctl_reg), CTL_EOL);
   1717   1.2  pgoyette 	if (node != NULL)
   1718   1.2  pgoyette 		node->sysctl_data = sc;
   1719   1.2  pgoyette 
   1720   1.2  pgoyette 	/* Fans do not have a high limit */
   1721  1.13  christos 	if (sc->sc_dc.dc_chip->table[idx].type == DBC_FAN)
   1722   1.2  pgoyette 		return 0;
   1723   1.2  pgoyette 
   1724   1.2  pgoyette 	sysctl_reg = sc->sc_regs[idx]->hi_lim_reg;
   1725   1.2  pgoyette 	ret = sysctl_createv(NULL, 0, NULL,
   1726   1.2  pgoyette 			(const struct sysctlnode **)&node,
   1727   1.2  pgoyette 			CTLFLAG_READWRITE,
   1728   1.2  pgoyette 			CTLTYPE_INT, "hi_lim", NULL, helper, 0, sc, 0,
   1729   1.2  pgoyette 			CTL_HW, me->sysctl_num, me2->sysctl_num,
   1730   1.2  pgoyette 			DBC_PWM_SYSCTL(idx, sysctl_reg), CTL_EOL);
   1731   1.2  pgoyette 	if (node != NULL)
   1732   1.2  pgoyette 		node->sysctl_data = sc;
   1733   1.2  pgoyette 
   1734   1.2  pgoyette 	return 0;
   1735   1.2  pgoyette }
   1736   1.2  pgoyette 
   1737   1.2  pgoyette static void
   1738   1.2  pgoyette dbcool_setup_controllers(struct dbcool_softc *sc, const struct sysctlnode *me,
   1739   1.2  pgoyette 			 int rw_flag, int ro_flag)
   1740   1.2  pgoyette {
   1741   1.2  pgoyette 	int i, j, ret;
   1742   1.2  pgoyette 	uint8_t sysctl_reg;
   1743   1.2  pgoyette 	const struct sysctlnode *me2 = NULL;
   1744   1.2  pgoyette 	struct sysctlnode *node = NULL;
   1745   1.2  pgoyette 	char name[SYSCTL_NAMELEN];
   1746   1.1  pgoyette 
   1747  1.13  christos 	for (i = 0; sc->sc_dc.dc_chip->power[i].desc != NULL; i++) {
   1748   1.2  pgoyette 		snprintf(name, sizeof(name), "fan_ctl_%d", i);
   1749   1.2  pgoyette 		ret = sysctl_createv(NULL, 0, NULL, &me2,
   1750   1.2  pgoyette 		       rw_flag,
   1751   1.2  pgoyette 		       CTLTYPE_NODE, name, NULL,
   1752   1.2  pgoyette 		       NULL, 0, NULL, 0,
   1753   1.2  pgoyette 		       CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL);
   1754   1.1  pgoyette 
   1755   1.2  pgoyette 		for (j = DBC_PWM_BEHAVIOR; j < DBC_PWM_LAST_PARAM; j++) {
   1756   1.2  pgoyette 			if (j == DBC_PWM_MAX_DUTY &&
   1757  1.13  christos 			    (sc->sc_dc.dc_chip->flags & DBCFLAG_HAS_MAXDUTY) == 0)
   1758   1.2  pgoyette 				continue;
   1759  1.13  christos 			sysctl_reg = sc->sc_dc.dc_chip->power[i].power_regs[j];
   1760   1.2  pgoyette 			if (sysctl_reg == DBCOOL_NO_REG)
   1761   1.2  pgoyette 				continue;
   1762   1.2  pgoyette 			strlcpy(name, dbc_sysctl_table[j].name, sizeof(name));
   1763   1.2  pgoyette 			ret = sysctl_createv(NULL, 0, NULL,
   1764   1.1  pgoyette 				(const struct sysctlnode **)&node,
   1765   1.2  pgoyette 				(dbc_sysctl_table[j].lockable)?ro_flag:rw_flag,
   1766   1.2  pgoyette 				(j == DBC_PWM_BEHAVIOR)?
   1767   1.2  pgoyette 					CTLTYPE_STRING:CTLTYPE_INT,
   1768   1.2  pgoyette 				name,
   1769   1.2  pgoyette 				dbc_sysctl_table[j].desc,
   1770   1.2  pgoyette 				dbc_sysctl_table[j].helper,
   1771   1.2  pgoyette 				0, sc,
   1772   1.2  pgoyette 				( j == DBC_PWM_BEHAVIOR)?
   1773   1.2  pgoyette 					sizeof(dbcool_cur_behav): sizeof(int),
   1774   1.1  pgoyette 				CTL_HW, me->sysctl_num, me2->sysctl_num,
   1775   1.2  pgoyette 				DBC_PWM_SYSCTL(j, sysctl_reg), CTL_EOL);
   1776   1.2  pgoyette 			if (node != NULL)
   1777   1.2  pgoyette 				node->sysctl_data = sc;
   1778   1.1  pgoyette 		}
   1779   1.1  pgoyette 	}
   1780   1.1  pgoyette }
   1781   1.1  pgoyette 
   1782   1.1  pgoyette static void
   1783   1.1  pgoyette dbcool_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
   1784   1.1  pgoyette {
   1785   1.1  pgoyette 	struct dbcool_softc *sc=sme->sme_cookie;
   1786   1.2  pgoyette 	int i, nom_volt_idx;
   1787   1.1  pgoyette 	int cur, hi, low;
   1788   1.1  pgoyette 	struct reg_list *reg;
   1789   1.1  pgoyette 
   1790   1.1  pgoyette 	i = edata->sensor;
   1791   1.1  pgoyette 	reg = sc->sc_regs[i];
   1792   1.1  pgoyette 	switch (edata->units)
   1793   1.1  pgoyette 	{
   1794   1.1  pgoyette 		case ENVSYS_STEMP:
   1795   1.1  pgoyette 			cur = dbcool_read_temp(sc, reg->val_reg, true);
   1796   1.1  pgoyette 			low = dbcool_read_temp(sc, reg->lo_lim_reg, false);
   1797   1.1  pgoyette 			hi  = dbcool_read_temp(sc, reg->hi_lim_reg, false);
   1798   1.1  pgoyette 			break;
   1799   1.1  pgoyette 		case ENVSYS_SVOLTS_DC:
   1800   1.2  pgoyette 			nom_volt_idx = sc->sc_nom_volt[i];
   1801   1.2  pgoyette 			cur = dbcool_read_volt(sc, reg->val_reg, nom_volt_idx,
   1802   1.2  pgoyette 						true);
   1803   1.2  pgoyette 			low = dbcool_read_volt(sc, reg->lo_lim_reg,
   1804   1.2  pgoyette 						nom_volt_idx, false);
   1805   1.2  pgoyette 			hi  = dbcool_read_volt(sc, reg->hi_lim_reg,
   1806   1.2  pgoyette 						nom_volt_idx, false);
   1807   1.1  pgoyette 			break;
   1808   1.1  pgoyette 		case ENVSYS_SFANRPM:
   1809   1.1  pgoyette 			cur = dbcool_read_rpm(sc, reg->val_reg);
   1810   1.1  pgoyette 			low = dbcool_read_rpm(sc, reg->lo_lim_reg);
   1811   1.1  pgoyette 			hi  = 1 << 16;
   1812   1.1  pgoyette 			break;
   1813   1.1  pgoyette 		default:
   1814   1.1  pgoyette 			edata->state = ENVSYS_SINVALID;
   1815   1.1  pgoyette 			return;
   1816   1.1  pgoyette 	}
   1817   1.1  pgoyette 
   1818   1.1  pgoyette 	if (cur == 0 && edata->units != ENVSYS_SFANRPM)
   1819   1.1  pgoyette 		edata->state = ENVSYS_SINVALID;
   1820   1.1  pgoyette 
   1821   1.1  pgoyette 	/* Make sure limits are sensible */
   1822   1.1  pgoyette 	else if (hi <= low)
   1823   1.1  pgoyette 		edata->state = ENVSYS_SVALID;
   1824   1.1  pgoyette 
   1825   1.1  pgoyette 	/*
   1826   1.1  pgoyette 	 * If fan is "stalled" but has no low limit, treat
   1827   1.1  pgoyette 	 * it as though the fan is not installed.
   1828   1.1  pgoyette 	 */
   1829   1.1  pgoyette 	else if (edata->units == ENVSYS_SFANRPM && cur == 0 &&
   1830   1.1  pgoyette 			(low == 0 || low == -1))
   1831   1.1  pgoyette 		edata->state = ENVSYS_SINVALID;
   1832   1.1  pgoyette 
   1833   1.1  pgoyette 	/*
   1834   1.1  pgoyette 	 * Compare current value against the limits
   1835   1.1  pgoyette 	 */
   1836   1.1  pgoyette 	else if (cur < low)
   1837   1.1  pgoyette 		edata->state = ENVSYS_SCRITUNDER;
   1838   1.1  pgoyette 	else if (cur > hi)
   1839   1.1  pgoyette 		edata->state = ENVSYS_SCRITOVER;
   1840   1.1  pgoyette 	else
   1841   1.1  pgoyette 		edata->state = ENVSYS_SVALID;
   1842   1.1  pgoyette 
   1843   1.1  pgoyette 	edata->value_cur = cur;
   1844   1.1  pgoyette }
   1845   1.1  pgoyette 
   1846   1.1  pgoyette int
   1847  1.13  christos dbcool_chip_ident(struct dbcool_chipset *dc)
   1848   1.1  pgoyette {
   1849   1.1  pgoyette 	/* verify this is a supported dbCool chip */
   1850   1.1  pgoyette 	uint8_t c_id, d_id, r_id;
   1851   1.1  pgoyette 	int i;
   1852   1.1  pgoyette 
   1853  1.13  christos 	c_id = dc->dc_readreg(dc, DBCOOL_COMPANYID_REG);
   1854  1.13  christos 	d_id = dc->dc_readreg(dc, DBCOOL_DEVICEID_REG);
   1855  1.13  christos 	r_id = dc->dc_readreg(dc, DBCOOL_REVISION_REG);
   1856   1.1  pgoyette 
   1857   1.1  pgoyette 	for (i = 0; chip_table[i].company != 0; i++)
   1858   1.1  pgoyette 		if ((c_id == chip_table[i].company) &&
   1859   1.1  pgoyette 		    (d_id == chip_table[i].device ||
   1860  1.13  christos 		    chip_table[i].device == 0xff) &&
   1861   1.1  pgoyette 		    (r_id == chip_table[i].rev ||
   1862  1.13  christos 		    chip_table[i].rev == 0xff)) {
   1863  1.13  christos 			dc->dc_chip = &chip_table[i];
   1864   1.1  pgoyette 			return i;
   1865   1.1  pgoyette 		}
   1866   1.1  pgoyette 
   1867   1.1  pgoyette 	aprint_verbose("dbcool_chip_ident: addr 0x%02x c_id 0x%02x d_id 0x%02x"
   1868  1.13  christos 			" r_id 0x%02x: No match.\n", dc->dc_addr, c_id, d_id,
   1869   1.1  pgoyette 			r_id);
   1870   1.1  pgoyette 
   1871   1.1  pgoyette 	return -1;
   1872   1.1  pgoyette }
   1873