Home | History | Annotate | Line # | Download | only in i2c
dbcool.c revision 1.57
      1  1.57   thorpej /*	$NetBSD: dbcool.c,v 1.57 2021/01/17 21:42:35 thorpej 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.45   msaitoh /*
     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.27  pgoyette  *	http://www.smsc.com/media/Downloads_Public/Data_Sheets/6d103s.pdf
     48   1.1  pgoyette  *
     49   1.2  pgoyette  * (URLs are correct as of October 5, 2008)
     50   1.1  pgoyette  */
     51   1.1  pgoyette 
     52   1.1  pgoyette #include <sys/cdefs.h>
     53  1.57   thorpej __KERNEL_RCSID(0, "$NetBSD: dbcool.c,v 1.57 2021/01/17 21:42:35 thorpej Exp $");
     54   1.1  pgoyette 
     55   1.1  pgoyette #include <sys/param.h>
     56   1.1  pgoyette #include <sys/systm.h>
     57   1.1  pgoyette #include <sys/kernel.h>
     58   1.1  pgoyette #include <sys/device.h>
     59   1.1  pgoyette #include <sys/malloc.h>
     60   1.1  pgoyette #include <sys/sysctl.h>
     61  1.31  jmcneill #include <sys/module.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.46   msaitoh 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.18  pgoyette /* Sensor get/set limit functions */
     82  1.18  pgoyette static void dbcool_get_limits(struct sysmon_envsys *, envsys_data_t *,
     83  1.18  pgoyette 			      sysmon_envsys_lim_t *, uint32_t *);
     84  1.18  pgoyette static void dbcool_get_temp_limits(struct dbcool_softc *, int,
     85  1.18  pgoyette 				   sysmon_envsys_lim_t *, uint32_t *);
     86  1.18  pgoyette static void dbcool_get_volt_limits(struct dbcool_softc *, int,
     87  1.18  pgoyette 				   sysmon_envsys_lim_t *, uint32_t *);
     88  1.18  pgoyette static void dbcool_get_fan_limits(struct dbcool_softc *, int,
     89  1.18  pgoyette 				  sysmon_envsys_lim_t *, uint32_t *);
     90  1.18  pgoyette 
     91  1.18  pgoyette static void dbcool_set_limits(struct sysmon_envsys *, envsys_data_t *,
     92  1.18  pgoyette 			      sysmon_envsys_lim_t *, uint32_t *);
     93  1.18  pgoyette static void dbcool_set_temp_limits(struct dbcool_softc *, int,
     94  1.18  pgoyette 				   sysmon_envsys_lim_t *, uint32_t *);
     95  1.18  pgoyette static void dbcool_set_volt_limits(struct dbcool_softc *, int,
     96  1.18  pgoyette 				   sysmon_envsys_lim_t *, uint32_t *);
     97  1.18  pgoyette static void dbcool_set_fan_limits(struct dbcool_softc *, int,
     98  1.18  pgoyette 				  sysmon_envsys_lim_t *, uint32_t *);
     99  1.18  pgoyette 
    100   1.1  pgoyette /* SYSCTL Helpers */
    101  1.33  pgoyette SYSCTL_SETUP_PROTO(sysctl_dbcoolsetup);
    102   1.2  pgoyette static int sysctl_dbcool_temp(SYSCTLFN_PROTO);
    103   1.2  pgoyette static int sysctl_adm1030_temp(SYSCTLFN_PROTO);
    104   1.1  pgoyette static int sysctl_adm1030_trange(SYSCTLFN_PROTO);
    105   1.1  pgoyette static int sysctl_dbcool_duty(SYSCTLFN_PROTO);
    106   1.1  pgoyette static int sysctl_dbcool_behavior(SYSCTLFN_PROTO);
    107   1.2  pgoyette static int sysctl_dbcool_slope(SYSCTLFN_PROTO);
    108   1.1  pgoyette static int sysctl_dbcool_thyst(SYSCTLFN_PROTO);
    109   1.1  pgoyette 
    110   1.2  pgoyette /* Set-up subroutines */
    111  1.18  pgoyette static void dbcool_setup_controllers(struct dbcool_softc *);
    112  1.18  pgoyette static int  dbcool_setup_sensors(struct dbcool_softc *);
    113  1.18  pgoyette static int  dbcool_attach_sensor(struct dbcool_softc *, int);
    114  1.18  pgoyette static int  dbcool_attach_temp_control(struct dbcool_softc *, int,
    115  1.18  pgoyette 	struct chip_id *);
    116   1.2  pgoyette 
    117   1.1  pgoyette #ifdef DBCOOL_DEBUG
    118   1.1  pgoyette static int sysctl_dbcool_reg_select(SYSCTLFN_PROTO);
    119   1.1  pgoyette static int sysctl_dbcool_reg_access(SYSCTLFN_PROTO);
    120   1.1  pgoyette #endif /* DBCOOL_DEBUG */
    121   1.1  pgoyette 
    122   1.1  pgoyette /*
    123   1.1  pgoyette  * Descriptions for SYSCTL entries
    124   1.1  pgoyette  */
    125   1.2  pgoyette struct dbc_sysctl_info {
    126   1.1  pgoyette 	const char *name;
    127   1.1  pgoyette 	const char *desc;
    128   1.2  pgoyette 	bool lockable;
    129   1.1  pgoyette 	int (*helper)(SYSCTLFN_PROTO);
    130   1.1  pgoyette };
    131   1.1  pgoyette 
    132   1.2  pgoyette static struct dbc_sysctl_info dbc_sysctl_table[] = {
    133   1.2  pgoyette 	/*
    134  1.45   msaitoh 	 * The first several entries must remain in the same order as the
    135   1.2  pgoyette 	 * corresponding entries in enum dbc_pwm_params
    136   1.2  pgoyette 	 */
    137   1.1  pgoyette 	{ "behavior",		"operating behavior and temp selector",
    138   1.2  pgoyette 		true, sysctl_dbcool_behavior },
    139   1.1  pgoyette 	{ "min_duty",		"minimum fan controller PWM duty cycle",
    140   1.2  pgoyette 		true, sysctl_dbcool_duty },
    141   1.1  pgoyette 	{ "max_duty",		"maximum fan controller PWM duty cycle",
    142   1.2  pgoyette 		true, sysctl_dbcool_duty },
    143   1.1  pgoyette 	{ "cur_duty",		"current fan controller PWM duty cycle",
    144   1.2  pgoyette 		false, sysctl_dbcool_duty },
    145   1.2  pgoyette 
    146   1.2  pgoyette 	/*
    147   1.2  pgoyette 	 * The rest of these should be in the order in which they
    148   1.2  pgoyette 	 * are to be stored in the sysctl tree;  the table index is
    149   1.2  pgoyette 	 * used as the high-order bits of the sysctl_num to maintain
    150   1.2  pgoyette 	 * the sequence.
    151   1.2  pgoyette 	 *
    152   1.2  pgoyette 	 * If you rearrange the order of these items, be sure to
    153   1.2  pgoyette 	 * update the sysctl_index in the XXX_sensor_table[] for
    154   1.2  pgoyette 	 * the various chips!
    155   1.2  pgoyette 	 */
    156   1.2  pgoyette 	{ "Trange",		"temp slope/range to reach 100% duty cycle",
    157   1.2  pgoyette 		true, sysctl_dbcool_slope },
    158   1.1  pgoyette 	{ "Tmin",		"temp at which to start fan controller",
    159   1.2  pgoyette 		true, sysctl_dbcool_temp },
    160   1.1  pgoyette 	{ "Ttherm",		"temp at which THERM is asserted",
    161   1.2  pgoyette 		true, sysctl_dbcool_temp },
    162   1.1  pgoyette 	{ "Thyst",		"temp hysteresis for stopping fan controller",
    163   1.2  pgoyette 		true, sysctl_dbcool_thyst },
    164   1.1  pgoyette 	{ "Tmin",		"temp at which to start fan controller",
    165   1.2  pgoyette 		true, sysctl_adm1030_temp },
    166   1.2  pgoyette 	{ "Trange",		"temp slope/range to reach 100% duty cycle",
    167   1.2  pgoyette 		true, sysctl_adm1030_trange },
    168   1.1  pgoyette };
    169   1.1  pgoyette 
    170   1.1  pgoyette static const char *dbc_sensor_names[] = {
    171   1.2  pgoyette 	"l_temp",  "r1_temp", "r2_temp", "Vccp",   "Vcc",    "fan1",
    172   1.4  pgoyette 	"fan2",    "fan3",    "fan4",    "AIN1",   "AIN2",   "V2dot5",
    173  1.16  pgoyette 	"V5",      "V12",     "Vtt",     "Imon",   "VID"
    174   1.2  pgoyette };
    175   1.2  pgoyette 
    176   1.2  pgoyette /*
    177   1.2  pgoyette  * Following table derived from product data-sheets
    178   1.2  pgoyette  */
    179   1.2  pgoyette static int64_t nominal_voltages[] = {
    180   1.2  pgoyette 	-1,		/* Vcc can be either 3.3 or 5.0V
    181   1.2  pgoyette 			   at 3/4 scale                  */
    182   1.3  pgoyette 	 2249939,	/* Vccp         2.25V 3/4 scale  */
    183   1.3  pgoyette 	 2497436,	/* 2.5VIN       2.5V  3/4 scale  */
    184   1.3  pgoyette 	 5002466,	/* 5VIN         5V    3/4 scale  */
    185   1.2  pgoyette 	12000000,	/* 12VIN       12V    3/4 scale  */
    186   1.3  pgoyette 	 1690809,	/* Vtt, Imon    2.25V full scale */
    187   1.3  pgoyette 	 1689600,	/* AIN1, AIN2   2.25V full scale */
    188   1.3  pgoyette 	       0
    189   1.2  pgoyette };
    190   1.2  pgoyette 
    191   1.2  pgoyette /*
    192   1.2  pgoyette  * Sensor-type, { val-reg, hilim-reg, lolim-reg}, name-idx, sysctl-table-idx,
    193   1.2  pgoyette  *	nom-voltage-index
    194   1.2  pgoyette  */
    195   1.2  pgoyette struct dbcool_sensor ADT7490_sensor_table[] = {
    196   1.2  pgoyette 	{ DBC_TEMP, {	DBCOOL_LOCAL_TEMP,
    197   1.2  pgoyette 			DBCOOL_LOCAL_HIGHLIM,
    198   1.2  pgoyette 			DBCOOL_LOCAL_LOWLIM },		0, 0, 0 },
    199   1.2  pgoyette 	{ DBC_TEMP, {	DBCOOL_REMOTE1_TEMP,
    200   1.2  pgoyette 			DBCOOL_REMOTE1_HIGHLIM,
    201   1.2  pgoyette 			DBCOOL_REMOTE1_LOWLIM },	1, 0, 0 },
    202   1.2  pgoyette 	{ DBC_TEMP, {	DBCOOL_REMOTE2_TEMP,
    203   1.2  pgoyette 			DBCOOL_REMOTE2_HIGHLIM,
    204   1.2  pgoyette 			DBCOOL_REMOTE2_LOWLIM },	2, 0, 0 },
    205   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_VCCP,
    206   1.2  pgoyette 			DBCOOL_VCCP_HIGHLIM,
    207   1.2  pgoyette 			DBCOOL_VCCP_LOWLIM },		3, 0, 1 },
    208   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_VCC,
    209   1.2  pgoyette 			DBCOOL_VCC_HIGHLIM,
    210   1.2  pgoyette 			DBCOOL_VCC_LOWLIM },		4, 0, 0 },
    211   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_25VIN,
    212   1.2  pgoyette 			DBCOOL_25VIN_HIGHLIM,
    213   1.2  pgoyette 			DBCOOL_25VIN_LOWLIM },		11, 0, 2 },
    214   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_5VIN,
    215   1.2  pgoyette 			DBCOOL_5VIN_HIGHLIM,
    216   1.2  pgoyette 			DBCOOL_5VIN_LOWLIM },		12, 0, 3 },
    217   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_12VIN,
    218   1.2  pgoyette 			DBCOOL_12VIN_HIGHLIM,
    219   1.2  pgoyette 			DBCOOL_12VIN_LOWLIM },		13, 0, 4 },
    220   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_VTT,
    221   1.2  pgoyette 			DBCOOL_VTT_HIGHLIM,
    222   1.2  pgoyette 			DBCOOL_VTT_LOWLIM },		14, 0, 5 },
    223   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_IMON,
    224   1.2  pgoyette 			DBCOOL_IMON_HIGHLIM,
    225   1.2  pgoyette 			DBCOOL_IMON_LOWLIM },		15, 0, 5 },
    226   1.2  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN1_TACH_LSB,
    227   1.2  pgoyette 			DBCOOL_NO_REG,
    228   1.2  pgoyette 			DBCOOL_TACH1_MIN_LSB },		5, 0, 0 },
    229   1.2  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN2_TACH_LSB,
    230   1.2  pgoyette 			DBCOOL_NO_REG,
    231   1.2  pgoyette 			DBCOOL_TACH2_MIN_LSB },		6, 0, 0 },
    232   1.2  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN3_TACH_LSB,
    233   1.2  pgoyette 			DBCOOL_NO_REG,
    234   1.2  pgoyette 			DBCOOL_TACH3_MIN_LSB },		7, 0, 0 },
    235   1.2  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN4_TACH_LSB,
    236   1.2  pgoyette 			DBCOOL_NO_REG,
    237   1.2  pgoyette 			DBCOOL_TACH4_MIN_LSB },		8, 0, 0 },
    238  1.16  pgoyette 	{ DBC_VID,  {	DBCOOL_VID_REG,
    239  1.16  pgoyette 			DBCOOL_NO_REG,
    240  1.16  pgoyette 			DBCOOL_NO_REG },		16, 0, 0 },
    241   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_LOCAL_TMIN,
    242   1.2  pgoyette 			DBCOOL_NO_REG,
    243   1.2  pgoyette 			DBCOOL_NO_REG },		0, 5, 0 },
    244   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_LOCAL_TTHRESH,
    245   1.2  pgoyette 			DBCOOL_NO_REG,
    246   1.2  pgoyette 			DBCOOL_NO_REG },		0, 6, 0 },
    247   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_R1_LCL_TMIN_HYST | 0x80,
    248   1.2  pgoyette 			DBCOOL_NO_REG,
    249   1.2  pgoyette 			DBCOOL_NO_REG },		0, 7, 0 },
    250   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE1_TMIN,
    251   1.2  pgoyette 			DBCOOL_NO_REG,
    252   1.2  pgoyette 			DBCOOL_NO_REG },		1, 5, 0 },
    253   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE1_TTHRESH,
    254   1.2  pgoyette 			DBCOOL_NO_REG,
    255   1.2  pgoyette 			DBCOOL_NO_REG },		1, 6, 0 },
    256   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_R1_LCL_TMIN_HYST,
    257   1.2  pgoyette 			DBCOOL_NO_REG,
    258   1.2  pgoyette 			DBCOOL_NO_REG },		1, 7, 0 },
    259   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE2_TMIN,
    260   1.2  pgoyette 			DBCOOL_NO_REG,
    261   1.2  pgoyette 			DBCOOL_NO_REG },		2, 5, 0 },
    262   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE2_TTHRESH,
    263   1.2  pgoyette 			DBCOOL_NO_REG,
    264   1.2  pgoyette 			DBCOOL_NO_REG },		2, 6, 0 },
    265   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_R2_TMIN_HYST,
    266   1.2  pgoyette 			DBCOOL_NO_REG,
    267   1.2  pgoyette 			DBCOOL_NO_REG },		2, 7, 0 },
    268   1.2  pgoyette 	{ DBC_EOF,  { 0, 0, 0 }, 0, 0, 0 }
    269   1.2  pgoyette };
    270   1.2  pgoyette 
    271   1.2  pgoyette struct dbcool_sensor ADT7476_sensor_table[] = {
    272   1.2  pgoyette 	{ DBC_TEMP, {	DBCOOL_LOCAL_TEMP,
    273   1.2  pgoyette 			DBCOOL_LOCAL_HIGHLIM,
    274   1.2  pgoyette 			DBCOOL_LOCAL_LOWLIM },		0, 0, 0 },
    275   1.2  pgoyette 	{ DBC_TEMP, {	DBCOOL_REMOTE1_TEMP,
    276   1.2  pgoyette 			DBCOOL_REMOTE1_HIGHLIM,
    277   1.2  pgoyette 			DBCOOL_REMOTE1_LOWLIM },	1, 0, 0 },
    278   1.2  pgoyette 	{ DBC_TEMP, {	DBCOOL_REMOTE2_TEMP,
    279   1.2  pgoyette 			DBCOOL_REMOTE2_HIGHLIM,
    280   1.2  pgoyette 			DBCOOL_REMOTE2_LOWLIM },	2, 0, 0 },
    281   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_VCCP,
    282   1.2  pgoyette 			DBCOOL_VCCP_HIGHLIM,
    283   1.2  pgoyette 			DBCOOL_VCCP_LOWLIM },		3, 0, 1 },
    284   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_VCC,
    285   1.2  pgoyette 			DBCOOL_VCC_HIGHLIM,
    286   1.2  pgoyette 			DBCOOL_VCC_LOWLIM },		4, 0, 0 },
    287   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_25VIN,
    288   1.2  pgoyette 			DBCOOL_25VIN_HIGHLIM,
    289   1.2  pgoyette 			DBCOOL_25VIN_LOWLIM },		11, 0, 2 },
    290   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_5VIN,
    291   1.2  pgoyette 			DBCOOL_5VIN_HIGHLIM,
    292   1.2  pgoyette 			DBCOOL_5VIN_LOWLIM },		12, 0, 3 },
    293   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_12VIN,
    294   1.2  pgoyette 			DBCOOL_12VIN_HIGHLIM,
    295   1.2  pgoyette 			DBCOOL_12VIN_LOWLIM },		13, 0, 4 },
    296   1.2  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN1_TACH_LSB,
    297   1.2  pgoyette 			DBCOOL_NO_REG,
    298   1.2  pgoyette 			DBCOOL_TACH1_MIN_LSB },		5, 0, 0 },
    299   1.2  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN2_TACH_LSB,
    300   1.2  pgoyette 			DBCOOL_NO_REG,
    301   1.2  pgoyette 			DBCOOL_TACH2_MIN_LSB },		6, 0, 0 },
    302   1.2  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN3_TACH_LSB,
    303   1.2  pgoyette 			DBCOOL_NO_REG,
    304   1.2  pgoyette 			DBCOOL_TACH3_MIN_LSB },		7, 0, 0 },
    305   1.2  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN4_TACH_LSB,
    306   1.2  pgoyette 			DBCOOL_NO_REG,
    307   1.2  pgoyette 			DBCOOL_TACH4_MIN_LSB },		8, 0, 0 },
    308  1.16  pgoyette 	{ DBC_VID,  {	DBCOOL_VID_REG,
    309  1.16  pgoyette 			DBCOOL_NO_REG,
    310  1.16  pgoyette 			DBCOOL_NO_REG },		16, 0, 0 },
    311   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_LOCAL_TMIN,
    312   1.2  pgoyette 			DBCOOL_NO_REG,
    313   1.2  pgoyette 			DBCOOL_NO_REG },		0, 5, 0 },
    314   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_LOCAL_TTHRESH,
    315   1.2  pgoyette 			DBCOOL_NO_REG,
    316   1.2  pgoyette 			DBCOOL_NO_REG },		0, 6, 0 },
    317   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_R1_LCL_TMIN_HYST | 0x80,
    318   1.2  pgoyette 			DBCOOL_NO_REG,
    319   1.2  pgoyette 			DBCOOL_NO_REG },		0, 7, 0 },
    320   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE1_TMIN,
    321   1.2  pgoyette 			DBCOOL_NO_REG,
    322   1.2  pgoyette 			DBCOOL_NO_REG },		1, 5, 0 },
    323   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE1_TTHRESH,
    324   1.2  pgoyette 			DBCOOL_NO_REG,
    325   1.2  pgoyette 			DBCOOL_NO_REG },		1, 6, 0 },
    326   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_R1_LCL_TMIN_HYST,
    327   1.2  pgoyette 			DBCOOL_NO_REG,
    328   1.2  pgoyette 			DBCOOL_NO_REG },		1, 7, 0 },
    329   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE2_TMIN,
    330   1.2  pgoyette 			DBCOOL_NO_REG,
    331   1.2  pgoyette 			DBCOOL_NO_REG },		2, 5, 0 },
    332   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE2_TTHRESH,
    333   1.2  pgoyette 			DBCOOL_NO_REG,
    334   1.2  pgoyette 			DBCOOL_NO_REG },		2, 6, 0 },
    335   1.2  pgoyette 	{ DBC_CTL,  {	DBCOOL_R2_TMIN_HYST,
    336   1.2  pgoyette 			DBCOOL_NO_REG,
    337   1.2  pgoyette 			DBCOOL_NO_REG },		2, 7, 0 },
    338   1.2  pgoyette 	{ DBC_EOF,  { 0, 0, 0 }, 0, 0, 0 }
    339   1.1  pgoyette };
    340   1.1  pgoyette 
    341   1.1  pgoyette struct dbcool_sensor ADT7475_sensor_table[] = {
    342   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_LOCAL_TEMP,
    343   1.1  pgoyette 			DBCOOL_LOCAL_HIGHLIM,
    344   1.2  pgoyette 			DBCOOL_LOCAL_LOWLIM },		0, 0, 0 },
    345   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_REMOTE1_TEMP,
    346   1.1  pgoyette 			DBCOOL_REMOTE1_HIGHLIM,
    347   1.2  pgoyette 			DBCOOL_REMOTE1_LOWLIM },	1, 0, 0 },
    348   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_REMOTE2_TEMP,
    349   1.1  pgoyette 			DBCOOL_REMOTE2_HIGHLIM,
    350   1.2  pgoyette 			DBCOOL_REMOTE2_LOWLIM },	2, 0, 0 },
    351   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_VCCP,
    352   1.1  pgoyette 			DBCOOL_VCCP_HIGHLIM,
    353   1.2  pgoyette 			DBCOOL_VCCP_LOWLIM },		3, 0, 1 },
    354   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_VCC,
    355   1.1  pgoyette 			DBCOOL_VCC_HIGHLIM,
    356   1.2  pgoyette 			DBCOOL_VCC_LOWLIM },		4, 0, 0 },
    357   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN1_TACH_LSB,
    358   1.1  pgoyette 			DBCOOL_NO_REG,
    359   1.2  pgoyette 			DBCOOL_TACH1_MIN_LSB },		5, 0, 0 },
    360   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN2_TACH_LSB,
    361   1.1  pgoyette 			DBCOOL_NO_REG,
    362   1.2  pgoyette 			DBCOOL_TACH2_MIN_LSB },		6, 0, 0 },
    363   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN3_TACH_LSB,
    364   1.1  pgoyette 			DBCOOL_NO_REG,
    365   1.2  pgoyette 			DBCOOL_TACH3_MIN_LSB },		7, 0, 0 },
    366   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN4_TACH_LSB,
    367   1.1  pgoyette 			DBCOOL_NO_REG,
    368   1.2  pgoyette 			DBCOOL_TACH4_MIN_LSB },		8, 0, 0 },
    369   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_LOCAL_TMIN,
    370   1.1  pgoyette 			DBCOOL_NO_REG,
    371   1.2  pgoyette 			DBCOOL_NO_REG },		0, 5, 0 },
    372   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_LOCAL_TTHRESH,
    373   1.1  pgoyette 			DBCOOL_NO_REG,
    374   1.2  pgoyette 			DBCOOL_NO_REG },		0, 6, 0 },
    375   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_R1_LCL_TMIN_HYST | 0x80,
    376   1.1  pgoyette 			DBCOOL_NO_REG,
    377   1.2  pgoyette 			DBCOOL_NO_REG },		0, 7, 0 },
    378   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE1_TMIN,
    379   1.1  pgoyette 			DBCOOL_NO_REG,
    380   1.2  pgoyette 			DBCOOL_NO_REG },		1, 5, 0 },
    381   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE1_TTHRESH,
    382   1.1  pgoyette 			DBCOOL_NO_REG,
    383   1.2  pgoyette 			DBCOOL_NO_REG },		1, 6, 0 },
    384   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_R1_LCL_TMIN_HYST,
    385   1.1  pgoyette 			DBCOOL_NO_REG,
    386   1.2  pgoyette 			DBCOOL_NO_REG },		1, 7, 0 },
    387   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE2_TMIN,
    388   1.1  pgoyette 			DBCOOL_NO_REG,
    389   1.2  pgoyette 			DBCOOL_NO_REG },		2, 5, 0 },
    390   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE2_TTHRESH,
    391   1.1  pgoyette 			DBCOOL_NO_REG,
    392   1.2  pgoyette 			DBCOOL_NO_REG },		2, 6, 0 },
    393   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_R2_TMIN_HYST,
    394   1.1  pgoyette 			DBCOOL_NO_REG,
    395   1.2  pgoyette 			DBCOOL_NO_REG },		2, 7, 0 },
    396   1.2  pgoyette 	{ DBC_EOF,  { 0, 0, 0 }, 0, 0, 0 }
    397   1.1  pgoyette };
    398   1.1  pgoyette 
    399   1.1  pgoyette /*
    400   1.2  pgoyette  * The registers of dbcool_power_control must be in the same order as
    401   1.1  pgoyette  * in enum dbc_pwm_params
    402   1.1  pgoyette  */
    403   1.1  pgoyette struct dbcool_power_control ADT7475_power_table[] = {
    404   1.2  pgoyette 	{ { DBCOOL_PWM1_CTL, DBCOOL_PWM1_MINDUTY,
    405   1.2  pgoyette 	    DBCOOL_PWM1_MAXDUTY, DBCOOL_PWM1_CURDUTY },
    406   1.1  pgoyette 		"fan_control_1" },
    407   1.2  pgoyette 	{ { DBCOOL_PWM2_CTL, DBCOOL_PWM2_MINDUTY,
    408   1.2  pgoyette 	    DBCOOL_PWM2_MAXDUTY, DBCOOL_PWM2_CURDUTY },
    409   1.1  pgoyette 		"fan_control_2" },
    410  1.45   msaitoh 	{ { DBCOOL_PWM3_CTL, DBCOOL_PWM3_MINDUTY,
    411   1.2  pgoyette 	    DBCOOL_PWM3_MAXDUTY, DBCOOL_PWM3_CURDUTY },
    412   1.1  pgoyette 		"fan_control_3" },
    413   1.2  pgoyette 	{ { 0, 0, 0, 0 }, NULL }
    414   1.1  pgoyette };
    415   1.1  pgoyette 
    416   1.1  pgoyette struct dbcool_sensor ADT7466_sensor_table[] = {
    417   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_ADT7466_LCL_TEMP_MSB,
    418   1.1  pgoyette 			DBCOOL_ADT7466_LCL_TEMP_HILIM,
    419   1.2  pgoyette 			DBCOOL_ADT7466_LCL_TEMP_LOLIM }, 0,  0, 0 },
    420   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_ADT7466_REM_TEMP_MSB,
    421   1.1  pgoyette 			DBCOOL_ADT7466_REM_TEMP_HILIM,
    422   1.2  pgoyette 			DBCOOL_ADT7466_REM_TEMP_LOLIM }, 1,  0, 0 },
    423   1.1  pgoyette 	{ DBC_VOLT, {	DBCOOL_ADT7466_VCC,
    424   1.1  pgoyette 			DBCOOL_ADT7466_VCC_HILIM,
    425   1.2  pgoyette 			DBCOOL_ADT7466_VCC_LOLIM },	4,  0, 0 },
    426   1.1  pgoyette 	{ DBC_VOLT, {	DBCOOL_ADT7466_AIN1,
    427   1.1  pgoyette 			DBCOOL_ADT7466_AIN1_HILIM,
    428   1.2  pgoyette 			DBCOOL_ADT7466_AIN1_LOLIM },	9,  0, 6 },
    429   1.1  pgoyette 	{ DBC_VOLT, {	DBCOOL_ADT7466_AIN2,
    430   1.1  pgoyette 			DBCOOL_ADT7466_AIN2_HILIM,
    431   1.2  pgoyette 			DBCOOL_ADT7466_AIN2_LOLIM },	10, 0, 6 },
    432   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_ADT7466_FANA_LSB,
    433   1.1  pgoyette 			DBCOOL_NO_REG,
    434   1.2  pgoyette 			DBCOOL_ADT7466_FANA_LOLIM_LSB }, 5,  0, 0 },
    435   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_ADT7466_FANB_LSB,
    436   1.1  pgoyette 			DBCOOL_NO_REG,
    437   1.2  pgoyette 			DBCOOL_ADT7466_FANB_LOLIM_LSB }, 6,  0, 0 },
    438   1.2  pgoyette 	{ DBC_EOF,  { 0, 0, 0 }, 0, 0, 0 }
    439   1.1  pgoyette };
    440   1.1  pgoyette 
    441   1.1  pgoyette struct dbcool_sensor ADM1027_sensor_table[] = {
    442   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_LOCAL_TEMP,
    443   1.1  pgoyette 			DBCOOL_LOCAL_HIGHLIM,
    444   1.2  pgoyette 			DBCOOL_LOCAL_LOWLIM },		0, 0, 0 },
    445   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_REMOTE1_TEMP,
    446   1.1  pgoyette 			DBCOOL_REMOTE1_HIGHLIM,
    447   1.2  pgoyette 			DBCOOL_REMOTE1_LOWLIM },	1, 0, 0 },
    448   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_REMOTE2_TEMP,
    449   1.1  pgoyette 			DBCOOL_REMOTE2_HIGHLIM,
    450   1.2  pgoyette 			DBCOOL_REMOTE2_LOWLIM },	2, 0, 0 },
    451   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_VCCP,
    452   1.1  pgoyette 			DBCOOL_VCCP_HIGHLIM,
    453   1.2  pgoyette 			DBCOOL_VCCP_LOWLIM },		3, 0, 1 },
    454   1.2  pgoyette 	{ DBC_VOLT, {	DBCOOL_VCC,
    455   1.1  pgoyette 			DBCOOL_VCC_HIGHLIM,
    456   1.2  pgoyette 			DBCOOL_VCC_LOWLIM },		4, 0, 0 },
    457   1.1  pgoyette 	{ DBC_VOLT, {	DBCOOL_25VIN,
    458   1.1  pgoyette 			DBCOOL_25VIN_HIGHLIM,
    459   1.2  pgoyette 			DBCOOL_25VIN_LOWLIM },		11, 0, 2 },
    460   1.1  pgoyette 	{ DBC_VOLT, {	DBCOOL_5VIN,
    461   1.1  pgoyette 			DBCOOL_5VIN_HIGHLIM,
    462   1.2  pgoyette 			DBCOOL_5VIN_LOWLIM },		12, 0, 3 },
    463   1.1  pgoyette 	{ DBC_VOLT, {	DBCOOL_12VIN,
    464   1.1  pgoyette 			DBCOOL_12VIN_HIGHLIM,
    465   1.2  pgoyette 			DBCOOL_12VIN_LOWLIM },		13, 0, 4 },
    466   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN1_TACH_LSB,
    467   1.1  pgoyette 			DBCOOL_NO_REG,
    468   1.2  pgoyette 			DBCOOL_TACH1_MIN_LSB },		5, 0, 0 },
    469   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN2_TACH_LSB,
    470   1.1  pgoyette 			DBCOOL_NO_REG,
    471   1.2  pgoyette 			DBCOOL_TACH2_MIN_LSB },		6, 0, 0 },
    472   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN3_TACH_LSB,
    473   1.1  pgoyette 			DBCOOL_NO_REG,
    474   1.2  pgoyette 			DBCOOL_TACH3_MIN_LSB },		7, 0, 0 },
    475   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN4_TACH_LSB,
    476   1.1  pgoyette 			DBCOOL_NO_REG,
    477   1.2  pgoyette 			DBCOOL_TACH4_MIN_LSB },		8, 0, 0 },
    478  1.16  pgoyette 	{ DBC_VID,  {	DBCOOL_VID_REG,
    479  1.16  pgoyette 			DBCOOL_NO_REG,
    480  1.16  pgoyette 			DBCOOL_NO_REG },		16, 0, 0 },
    481   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_LOCAL_TMIN,
    482   1.1  pgoyette 			DBCOOL_NO_REG,
    483   1.2  pgoyette 			DBCOOL_NO_REG },		0, 5, 0 },
    484   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_LOCAL_TTHRESH,
    485   1.1  pgoyette 			DBCOOL_NO_REG,
    486   1.2  pgoyette 			DBCOOL_NO_REG },		0, 6, 0 },
    487   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_R1_LCL_TMIN_HYST | 0x80,
    488   1.1  pgoyette 			DBCOOL_NO_REG,
    489   1.2  pgoyette 			DBCOOL_NO_REG },		0, 7, 0 },
    490   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE1_TMIN,
    491   1.1  pgoyette 			DBCOOL_NO_REG,
    492   1.2  pgoyette 			DBCOOL_NO_REG },		1, 5, 0 },
    493   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE1_TTHRESH,
    494   1.1  pgoyette 			DBCOOL_NO_REG,
    495   1.2  pgoyette 			DBCOOL_NO_REG },		1, 6, 0 },
    496   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_R1_LCL_TMIN_HYST,
    497   1.1  pgoyette 			DBCOOL_NO_REG,
    498   1.2  pgoyette 			DBCOOL_NO_REG },		1, 7, 0 },
    499   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE2_TMIN,
    500   1.1  pgoyette 			DBCOOL_NO_REG,
    501   1.2  pgoyette 			DBCOOL_NO_REG },		2, 5, 0 },
    502   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE2_TTHRESH,
    503   1.1  pgoyette 			DBCOOL_NO_REG,
    504   1.2  pgoyette 			DBCOOL_NO_REG },		2, 6, 0 },
    505   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_R2_TMIN_HYST,
    506   1.1  pgoyette 			DBCOOL_NO_REG,
    507   1.2  pgoyette 			DBCOOL_NO_REG },		2, 7, 0 },
    508   1.2  pgoyette 	{ DBC_EOF,  { 0, 0, 0 }, 0, 0, 0 }
    509   1.1  pgoyette };
    510   1.1  pgoyette 
    511   1.1  pgoyette struct dbcool_sensor ADM1030_sensor_table[] = {
    512   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_ADM1030_L_TEMP,
    513   1.1  pgoyette 			DBCOOL_ADM1030_L_HI_LIM,
    514   1.2  pgoyette 			DBCOOL_ADM1030_L_LO_LIM },	0,  0, 0 },
    515   1.1  pgoyette 	{ DBC_TEMP, {	DBCOOL_ADM1030_R_TEMP,
    516   1.1  pgoyette 			DBCOOL_ADM1030_R_HI_LIM,
    517   1.2  pgoyette 			DBCOOL_ADM1030_R_LO_LIM },	1,  0, 0 },
    518   1.1  pgoyette 	{ DBC_FAN,  {	DBCOOL_ADM1030_FAN_TACH,
    519   1.1  pgoyette 			DBCOOL_NO_REG,
    520   1.2  pgoyette 			DBCOOL_ADM1030_FAN_LO_LIM },	5,  0, 0 },
    521   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_ADM1030_L_TMIN,
    522   1.1  pgoyette 			DBCOOL_NO_REG,
    523   1.2  pgoyette 			DBCOOL_NO_REG },		0,  8, 0 },
    524   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_ADM1030_L_TTHRESH,
    525   1.1  pgoyette 			DBCOOL_NO_REG,
    526   1.2  pgoyette 			DBCOOL_NO_REG },		0,  9, 0 },
    527   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_ADM1030_L_TTHRESH,
    528   1.1  pgoyette 			DBCOOL_NO_REG,
    529   1.2  pgoyette 			DBCOOL_NO_REG },		0,  6, 0 },
    530   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_ADM1030_R_TMIN,
    531   1.1  pgoyette 			DBCOOL_NO_REG,
    532   1.2  pgoyette 			DBCOOL_NO_REG },		1,  8, 0 },
    533  1.22  macallan 	{ DBC_CTL,  {	DBCOOL_ADM1030_R_TTHRESH,
    534   1.1  pgoyette 			DBCOOL_NO_REG,
    535   1.2  pgoyette 			DBCOOL_NO_REG },		1,  9, 0 },
    536   1.1  pgoyette 	{ DBC_CTL,  {	DBCOOL_ADM1030_R_TTHRESH,
    537   1.1  pgoyette 			DBCOOL_NO_REG,
    538   1.2  pgoyette 			DBCOOL_NO_REG },		1,  6, 0 },
    539   1.2  pgoyette 	{ DBC_EOF,  {0, 0, 0 }, 0, 0, 0 }
    540   1.1  pgoyette };
    541   1.1  pgoyette 
    542  1.45   msaitoh struct dbcool_power_control ADM1030_power_table[] = {
    543   1.2  pgoyette 	{ { DBCOOL_ADM1030_CFG1,  DBCOOL_NO_REG, DBCOOL_NO_REG,
    544   1.2  pgoyette 	    DBCOOL_ADM1030_FAN_SPEED_CFG },
    545   1.2  pgoyette 	  "fan_control_1" },
    546   1.2  pgoyette 	{ { 0, 0, 0, 0 }, NULL }
    547   1.1  pgoyette };
    548   1.1  pgoyette 
    549  1.22  macallan struct dbcool_sensor ADM1031_sensor_table[] = {
    550  1.22  macallan 	{ DBC_TEMP, {	DBCOOL_ADM1030_L_TEMP,
    551  1.22  macallan 			DBCOOL_ADM1030_L_HI_LIM,
    552  1.22  macallan 			DBCOOL_ADM1030_L_LO_LIM },	0,  0, 0 },
    553  1.22  macallan 	{ DBC_TEMP, {	DBCOOL_ADM1030_R_TEMP,
    554  1.22  macallan 			DBCOOL_ADM1030_R_HI_LIM,
    555  1.22  macallan 			DBCOOL_ADM1030_R_LO_LIM },	1,  0, 0 },
    556  1.22  macallan 	{ DBC_TEMP, {	DBCOOL_ADM1031_R2_TEMP,
    557  1.22  macallan 			DBCOOL_ADM1031_R2_HI_LIM,
    558  1.22  macallan 			DBCOOL_ADM1031_R2_LO_LIM },	2,  0, 0 },
    559  1.22  macallan 	{ DBC_FAN,  {	DBCOOL_ADM1030_FAN_TACH,
    560  1.22  macallan 			DBCOOL_NO_REG,
    561  1.22  macallan 			DBCOOL_ADM1030_FAN_LO_LIM },	5,  0, 0 },
    562  1.22  macallan 	{ DBC_FAN,  {	DBCOOL_ADM1031_FAN2_TACH,
    563  1.22  macallan 			DBCOOL_NO_REG,
    564  1.22  macallan 			DBCOOL_ADM1031_FAN2_LO_LIM },	6,  0, 0 },
    565  1.22  macallan 	{ DBC_CTL,  {	DBCOOL_ADM1030_L_TMIN,
    566  1.22  macallan 			DBCOOL_NO_REG,
    567  1.22  macallan 			DBCOOL_NO_REG },		0,  8, 0 },
    568  1.22  macallan 	{ DBC_CTL,  {	DBCOOL_ADM1030_L_TTHRESH,
    569  1.22  macallan 			DBCOOL_NO_REG,
    570  1.22  macallan 			DBCOOL_NO_REG },		0,  9, 0 },
    571  1.22  macallan 	{ DBC_CTL,  {	DBCOOL_ADM1030_L_TTHRESH,
    572  1.22  macallan 			DBCOOL_NO_REG,
    573  1.22  macallan 			DBCOOL_NO_REG },		0,  6, 0 },
    574  1.22  macallan 	{ DBC_CTL,  {	DBCOOL_ADM1030_R_TMIN,
    575  1.22  macallan 			DBCOOL_NO_REG,
    576  1.22  macallan 			DBCOOL_NO_REG },		1,  8, 0 },
    577  1.22  macallan 	{ DBC_CTL,  {	DBCOOL_ADM1030_R_TTHRESH,
    578  1.22  macallan 			DBCOOL_NO_REG,
    579  1.22  macallan 			DBCOOL_NO_REG },		1,  9, 0 },
    580  1.22  macallan 	{ DBC_CTL,  {	DBCOOL_ADM1030_R_TTHRESH,
    581  1.22  macallan 			DBCOOL_NO_REG,
    582  1.22  macallan 			DBCOOL_NO_REG },		1,  6, 0 },
    583  1.22  macallan 	{ DBC_CTL,  {	DBCOOL_ADM1031_R2_TMIN,
    584  1.22  macallan 			DBCOOL_NO_REG,
    585  1.22  macallan 			DBCOOL_NO_REG },		2,  8, 0 },
    586  1.22  macallan 	{ DBC_CTL,  {	DBCOOL_ADM1031_R2_TTHRESH,
    587  1.22  macallan 			DBCOOL_NO_REG,
    588  1.22  macallan 			DBCOOL_NO_REG },		2,  9, 0 },
    589  1.22  macallan 	{ DBC_CTL,  {	DBCOOL_ADM1031_R2_TTHRESH,
    590  1.22  macallan 			DBCOOL_NO_REG,
    591  1.22  macallan 			DBCOOL_NO_REG },		2,  6, 0 },
    592  1.22  macallan 	{ DBC_EOF,  {0, 0, 0 }, 0, 0, 0 }
    593  1.22  macallan };
    594  1.22  macallan 
    595  1.45   msaitoh struct dbcool_power_control ADM1031_power_table[] = {
    596  1.22  macallan 	{ { DBCOOL_ADM1030_CFG1,  DBCOOL_NO_REG, DBCOOL_NO_REG,
    597  1.22  macallan 	    DBCOOL_ADM1030_FAN_SPEED_CFG },
    598  1.22  macallan 	  "fan_control_1" },
    599  1.22  macallan 	{ { DBCOOL_ADM1030_CFG1,  DBCOOL_NO_REG, DBCOOL_NO_REG,
    600  1.22  macallan 	    DBCOOL_ADM1030_FAN_SPEED_CFG },
    601  1.22  macallan 	  "fan_control_2" },
    602  1.22  macallan 	{ { 0, 0, 0, 0 }, NULL }
    603  1.22  macallan };
    604  1.27  pgoyette 
    605  1.27  pgoyette struct dbcool_sensor EMC6D103S_sensor_table[] = {
    606  1.27  pgoyette 	{ DBC_TEMP, {	DBCOOL_LOCAL_TEMP,
    607  1.27  pgoyette 			DBCOOL_LOCAL_HIGHLIM,
    608  1.27  pgoyette 			DBCOOL_LOCAL_LOWLIM },		0, 0, 0 },
    609  1.27  pgoyette 	{ DBC_TEMP, {	DBCOOL_REMOTE1_TEMP,
    610  1.27  pgoyette 			DBCOOL_REMOTE1_HIGHLIM,
    611  1.27  pgoyette 			DBCOOL_REMOTE1_LOWLIM },	1, 0, 0 },
    612  1.27  pgoyette 	{ DBC_TEMP, {	DBCOOL_REMOTE2_TEMP,
    613  1.27  pgoyette 			DBCOOL_REMOTE2_HIGHLIM,
    614  1.27  pgoyette 			DBCOOL_REMOTE2_LOWLIM },	2, 0, 0 },
    615  1.27  pgoyette 	{ DBC_VOLT, {	DBCOOL_VCCP,
    616  1.27  pgoyette 			DBCOOL_VCCP_HIGHLIM,
    617  1.27  pgoyette 			DBCOOL_VCCP_LOWLIM },		3, 0, 1 },
    618  1.27  pgoyette 	{ DBC_VOLT, {	DBCOOL_VCC,
    619  1.27  pgoyette 			DBCOOL_VCC_HIGHLIM,
    620  1.27  pgoyette 			DBCOOL_VCC_LOWLIM },		4, 0, 0 },
    621  1.27  pgoyette 	{ DBC_VOLT, {	DBCOOL_25VIN,
    622  1.27  pgoyette 			DBCOOL_25VIN_HIGHLIM,
    623  1.27  pgoyette 			DBCOOL_25VIN_LOWLIM },		11, 0, 2 },
    624  1.27  pgoyette 	{ DBC_VOLT, {	DBCOOL_5VIN,
    625  1.27  pgoyette 			DBCOOL_5VIN_HIGHLIM,
    626  1.27  pgoyette 			DBCOOL_5VIN_LOWLIM },		12, 0, 3 },
    627  1.27  pgoyette 	{ DBC_VOLT, {	DBCOOL_12VIN,
    628  1.27  pgoyette 			DBCOOL_12VIN_HIGHLIM,
    629  1.27  pgoyette 			DBCOOL_12VIN_LOWLIM },		13, 0, 4 },
    630  1.27  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN1_TACH_LSB,
    631  1.27  pgoyette 			DBCOOL_NO_REG,
    632  1.27  pgoyette 			DBCOOL_TACH1_MIN_LSB },		5, 0, 0 },
    633  1.27  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN2_TACH_LSB,
    634  1.27  pgoyette 			DBCOOL_NO_REG,
    635  1.27  pgoyette 			DBCOOL_TACH2_MIN_LSB },		6, 0, 0 },
    636  1.27  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN3_TACH_LSB,
    637  1.27  pgoyette 			DBCOOL_NO_REG,
    638  1.27  pgoyette 			DBCOOL_TACH3_MIN_LSB },		7, 0, 0 },
    639  1.27  pgoyette 	{ DBC_FAN,  {	DBCOOL_FAN4_TACH_LSB,
    640  1.27  pgoyette 			DBCOOL_NO_REG,
    641  1.27  pgoyette 			DBCOOL_TACH4_MIN_LSB },		8, 0, 0 },
    642  1.27  pgoyette 	{ DBC_VID,  {	DBCOOL_VID_REG,
    643  1.27  pgoyette 			DBCOOL_NO_REG,
    644  1.27  pgoyette 			DBCOOL_NO_REG },		16, 0, 0 },
    645  1.27  pgoyette 	{ DBC_CTL,  {	DBCOOL_LOCAL_TMIN,
    646  1.27  pgoyette 			DBCOOL_NO_REG,
    647  1.27  pgoyette 			DBCOOL_NO_REG },		0, 5, 0 },
    648  1.27  pgoyette 	{ DBC_CTL,  {	DBCOOL_LOCAL_TTHRESH,
    649  1.27  pgoyette 			DBCOOL_NO_REG,
    650  1.27  pgoyette 			DBCOOL_NO_REG },		0, 6, 0 },
    651  1.27  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE1_TMIN,
    652  1.27  pgoyette 			DBCOOL_NO_REG,
    653  1.27  pgoyette 			DBCOOL_NO_REG },		1, 5, 0 },
    654  1.27  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE1_TTHRESH,
    655  1.27  pgoyette 			DBCOOL_NO_REG,
    656  1.27  pgoyette 			DBCOOL_NO_REG },		1, 6, 0 },
    657  1.27  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE2_TMIN,
    658  1.27  pgoyette 			DBCOOL_NO_REG,
    659  1.27  pgoyette 			DBCOOL_NO_REG },		2, 5, 0 },
    660  1.27  pgoyette 	{ DBC_CTL,  {	DBCOOL_REMOTE2_TTHRESH,
    661  1.27  pgoyette 			DBCOOL_NO_REG,
    662  1.27  pgoyette 			DBCOOL_NO_REG },		2, 6, 0 },
    663  1.27  pgoyette 	{ DBC_EOF,  { 0, 0, 0 }, 0, 0, 0 }
    664  1.27  pgoyette };
    665  1.27  pgoyette 
    666   1.1  pgoyette struct chip_id chip_table[] = {
    667   1.2  pgoyette 	{ DBCOOL_COMPANYID, ADT7490_DEVICEID, ADT7490_REV_ID,
    668  1.16  pgoyette 		ADT7490_sensor_table, ADT7475_power_table,
    669  1.16  pgoyette 		DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_PECI,
    670   1.2  pgoyette 		90000 * 60, "ADT7490" },
    671   1.1  pgoyette 	{ DBCOOL_COMPANYID, ADT7476_DEVICEID, 0xff,
    672   1.2  pgoyette 		ADT7476_sensor_table, ADT7475_power_table,
    673  1.16  pgoyette 		DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY,
    674   1.1  pgoyette 		90000 * 60, "ADT7476" },
    675   1.1  pgoyette 	{ DBCOOL_COMPANYID, ADT7475_DEVICEID, 0xff,
    676   1.1  pgoyette 		ADT7475_sensor_table, ADT7475_power_table,
    677   1.1  pgoyette 		DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_SHDN,
    678   1.1  pgoyette 		90000 * 60, "ADT7475" },
    679   1.2  pgoyette 	{ DBCOOL_COMPANYID, ADT7473_DEVICEID, ADT7473_REV_ID1,
    680   1.1  pgoyette 		ADT7475_sensor_table, ADT7475_power_table,
    681   1.1  pgoyette 		DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_SHDN,
    682   1.8  pgoyette 		90000 * 60, "ADT7460/ADT7463" },
    683   1.2  pgoyette 	{ DBCOOL_COMPANYID, ADT7473_DEVICEID, ADT7473_REV_ID2,
    684   1.1  pgoyette 		ADT7475_sensor_table, ADT7475_power_table,
    685   1.1  pgoyette 		DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_SHDN,
    686   1.1  pgoyette 		90000 * 60, "ADT7463-1" },
    687   1.1  pgoyette 	{ DBCOOL_COMPANYID, ADT7468_DEVICEID, 0xff,
    688   1.2  pgoyette 		ADT7476_sensor_table, ADT7475_power_table,
    689   1.1  pgoyette 		DBCFLAG_TEMPOFFSET  | DBCFLAG_MULTI_VCC | DBCFLAG_HAS_MAXDUTY |
    690  1.16  pgoyette 		    DBCFLAG_4BIT_VER | DBCFLAG_HAS_SHDN,
    691   1.2  pgoyette 		90000 * 60, "ADT7467/ADT7468" },
    692   1.1  pgoyette 	{ DBCOOL_COMPANYID, ADT7466_DEVICEID, 0xff,
    693   1.1  pgoyette 		ADT7466_sensor_table, NULL,
    694   1.1  pgoyette 		DBCFLAG_ADT7466 | DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_SHDN,
    695   1.1  pgoyette 		82000 * 60, "ADT7466" },
    696   1.1  pgoyette 	{ DBCOOL_COMPANYID, ADT7463_DEVICEID, ADT7463_REV_ID1,
    697   1.1  pgoyette 		ADM1027_sensor_table, ADT7475_power_table,
    698  1.16  pgoyette 		DBCFLAG_MULTI_VCC | DBCFLAG_4BIT_VER | DBCFLAG_HAS_SHDN,
    699   1.1  pgoyette 		90000 * 60, "ADT7463" },
    700   1.1  pgoyette 	{ DBCOOL_COMPANYID, ADT7463_DEVICEID, ADT7463_REV_ID2,
    701   1.1  pgoyette 		ADM1027_sensor_table, ADT7475_power_table,
    702   1.1  pgoyette 		DBCFLAG_MULTI_VCC | DBCFLAG_4BIT_VER | DBCFLAG_HAS_SHDN |
    703  1.16  pgoyette 		    DBCFLAG_HAS_VID_SEL,
    704   1.1  pgoyette 		90000 * 60, "ADT7463" },
    705   1.1  pgoyette 	{ DBCOOL_COMPANYID, ADM1027_DEVICEID, ADM1027_REV_ID,
    706   1.1  pgoyette 		ADM1027_sensor_table, ADT7475_power_table,
    707  1.16  pgoyette 		DBCFLAG_MULTI_VCC | DBCFLAG_4BIT_VER,
    708   1.1  pgoyette 		90000 * 60, "ADM1027" },
    709   1.1  pgoyette 	{ DBCOOL_COMPANYID, ADM1030_DEVICEID, 0xff,
    710   1.1  pgoyette 		ADM1030_sensor_table, ADM1030_power_table,
    711  1.16  pgoyette 		DBCFLAG_ADM1030 | DBCFLAG_NO_READBYTE,
    712   1.1  pgoyette 		11250 * 60, "ADM1030" },
    713  1.21  macallan 	{ DBCOOL_COMPANYID, ADM1031_DEVICEID, 0xff,
    714  1.22  macallan 		ADM1031_sensor_table, ADM1030_power_table,
    715  1.21  macallan 		DBCFLAG_ADM1030 | DBCFLAG_NO_READBYTE,
    716  1.21  macallan 		11250 * 60, "ADM1031" },
    717  1.27  pgoyette 	{ SMSC_COMPANYID, EMC6D103S_DEVICEID, EMC6D103S_REV_ID,
    718  1.27  pgoyette 		EMC6D103S_sensor_table, ADT7475_power_table,
    719  1.27  pgoyette 		DBCFLAG_4BIT_VER,
    720  1.27  pgoyette 		90000 * 60, "EMC6D103S" },
    721   1.1  pgoyette 	{ 0, 0, 0, NULL, NULL, 0, 0, NULL }
    722   1.1  pgoyette };
    723   1.1  pgoyette 
    724   1.1  pgoyette static const char *behavior[] = {
    725   1.1  pgoyette 	"remote1",	"local",	"remote2",	"full-speed",
    726   1.1  pgoyette 	"disabled",	"local+remote2","all-temps",	"manual"
    727   1.1  pgoyette };
    728   1.1  pgoyette 
    729   1.1  pgoyette static char dbcool_cur_behav[16];
    730   1.1  pgoyette 
    731   1.1  pgoyette CFATTACH_DECL_NEW(dbcool, sizeof(struct dbcool_softc),
    732   1.1  pgoyette     dbcool_match, dbcool_attach, dbcool_detach, NULL);
    733   1.1  pgoyette 
    734  1.52   thorpej static const struct device_compatible_entry compat_data[] = {
    735  1.57   thorpej 	{ .compat = "i2c-adm1031" },
    736  1.57   thorpej 	{ .compat = "adt7467" },
    737  1.57   thorpej 	{ .compat = "adt7460" },
    738  1.57   thorpej 	{ .compat = "adm1030" },
    739  1.57   thorpej 
    740  1.57   thorpej 	{ 0 }
    741  1.50   thorpej };
    742  1.50   thorpej 
    743   1.1  pgoyette int
    744   1.1  pgoyette dbcool_match(device_t parent, cfdata_t cf, void *aux)
    745   1.1  pgoyette {
    746   1.1  pgoyette 	struct i2c_attach_args *ia = aux;
    747  1.13  christos 	struct dbcool_chipset dc;
    748  1.13  christos 	dc.dc_tag = ia->ia_tag;
    749  1.13  christos 	dc.dc_addr = ia->ia_addr;
    750  1.13  christos 	dc.dc_chip = NULL;
    751  1.13  christos 	dc.dc_readreg = dbcool_readreg;
    752  1.13  christos 	dc.dc_writereg = dbcool_writereg;
    753  1.49   thorpej 	int match_result;
    754  1.49   thorpej 
    755  1.52   thorpej 	if (iic_use_direct_match(ia, cf, compat_data, &match_result))
    756  1.49   thorpej 		return match_result;
    757  1.49   thorpej 
    758  1.49   thorpej 	if ((ia->ia_addr & DBCOOL_ADDRMASK) != DBCOOL_ADDR)
    759  1.49   thorpej 		return 0;
    760  1.49   thorpej 	if (dbcool_chip_ident(&dc) >= 0)
    761  1.49   thorpej 		return I2C_MATCH_ADDRESS_AND_PROBE;
    762   1.1  pgoyette 
    763   1.1  pgoyette 	return 0;
    764   1.1  pgoyette }
    765   1.1  pgoyette 
    766   1.1  pgoyette void
    767   1.1  pgoyette dbcool_attach(device_t parent, device_t self, void *aux)
    768   1.1  pgoyette {
    769   1.1  pgoyette 	struct dbcool_softc *sc = device_private(self);
    770   1.1  pgoyette 	struct i2c_attach_args *args = aux;
    771   1.1  pgoyette 	uint8_t ver;
    772   1.1  pgoyette 
    773  1.13  christos 	sc->sc_dc.dc_addr = args->ia_addr;
    774  1.13  christos 	sc->sc_dc.dc_tag = args->ia_tag;
    775  1.13  christos 	sc->sc_dc.dc_chip = NULL;
    776  1.13  christos 	sc->sc_dc.dc_readreg = dbcool_readreg;
    777  1.13  christos 	sc->sc_dc.dc_writereg = dbcool_writereg;
    778   1.2  pgoyette 	sc->sc_dev = self;
    779  1.55  macallan 	sc->sc_prop = args->ia_prop;
    780   1.1  pgoyette 
    781  1.51    martin 	if (dbcool_chip_ident(&sc->sc_dc) < 0 || sc->sc_dc.dc_chip == NULL)
    782  1.51    martin 		panic("could not identify chip at addr %d", args->ia_addr);
    783  1.51    martin 
    784   1.1  pgoyette 	aprint_naive("\n");
    785   1.1  pgoyette 	aprint_normal("\n");
    786   1.1  pgoyette 
    787  1.13  christos 	ver = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_REVISION_REG);
    788  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_4BIT_VER)
    789  1.27  pgoyette 	        if (sc->sc_dc.dc_chip->company == SMSC_COMPANYID)
    790  1.27  pgoyette 	        {
    791  1.27  pgoyette 		        aprint_normal_dev(self, "SMSC %s Controller "
    792  1.45   msaitoh 			    "(rev 0x%02x, stepping 0x%02x)\n",
    793  1.45   msaitoh 			    sc->sc_dc.dc_chip->name, ver >> 4, ver & 0x0f);
    794  1.27  pgoyette 	        } else {
    795  1.27  pgoyette 		        aprint_normal_dev(self, "%s dBCool(tm) Controller "
    796  1.45   msaitoh 			    "(rev 0x%02x, stepping 0x%02x)\n",
    797  1.45   msaitoh 			    sc->sc_dc.dc_chip->name, ver >> 4, ver & 0x0f);
    798  1.27  pgoyette                 }
    799   1.1  pgoyette 	else
    800   1.1  pgoyette 		aprint_normal_dev(self, "%s dBCool(tm) Controller "
    801  1.13  christos 			"(rev 0x%04x)\n", sc->sc_dc.dc_chip->name, ver);
    802   1.1  pgoyette 
    803  1.33  pgoyette 	sc->sc_sysctl_log = NULL;
    804  1.33  pgoyette 
    805  1.33  pgoyette #ifdef _MODULE
    806  1.33  pgoyette 	sysctl_dbcoolsetup(&sc->sc_sysctl_log);
    807  1.33  pgoyette #endif
    808  1.33  pgoyette 
    809   1.1  pgoyette 	dbcool_setup(self);
    810   1.1  pgoyette 
    811   1.1  pgoyette 	if (!pmf_device_register(self, dbcool_pmf_suspend, dbcool_pmf_resume))
    812   1.1  pgoyette 		aprint_error_dev(self, "couldn't establish power handler\n");
    813   1.1  pgoyette }
    814   1.1  pgoyette 
    815   1.1  pgoyette static int
    816   1.1  pgoyette dbcool_detach(device_t self, int flags)
    817   1.1  pgoyette {
    818   1.1  pgoyette 	struct dbcool_softc *sc = device_private(self);
    819   1.1  pgoyette 
    820  1.31  jmcneill 	pmf_device_deregister(self);
    821  1.31  jmcneill 
    822   1.1  pgoyette 	sysmon_envsys_unregister(sc->sc_sme);
    823  1.33  pgoyette 
    824  1.33  pgoyette 	sysctl_teardown(&sc->sc_sysctl_log);
    825  1.33  pgoyette 
    826   1.1  pgoyette 	sc->sc_sme = NULL;
    827   1.1  pgoyette 	return 0;
    828   1.1  pgoyette }
    829   1.1  pgoyette 
    830  1.53       mrg /*
    831  1.53       mrg  * On suspend, we save the state of the SHDN bit, then set it
    832  1.53       mrg  * On resume, we restore the previous state of the SHDN bit (which
    833  1.53       mrg  * we saved in sc_suspend)
    834  1.53       mrg  */
    835  1.53       mrg static bool
    836  1.53       mrg dbcool_do_pmf(device_t dev, const pmf_qual_t *qual, bool suspend)
    837   1.1  pgoyette {
    838   1.1  pgoyette 	struct dbcool_softc *sc = device_private(dev);
    839   1.1  pgoyette 	uint8_t reg, bit, cfg;
    840   1.1  pgoyette 
    841  1.36       wiz 	if ((sc->sc_dc.dc_chip->flags & DBCFLAG_HAS_SHDN) == 0)
    842   1.1  pgoyette 		return true;
    843  1.45   msaitoh 
    844  1.36       wiz 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) {
    845   1.1  pgoyette 		reg = DBCOOL_ADT7466_CONFIG2;
    846   1.1  pgoyette 		bit = DBCOOL_ADT7466_CFG2_SHDN;
    847   1.1  pgoyette 	} else {
    848   1.1  pgoyette 		reg = DBCOOL_CONFIG2_REG;
    849   1.1  pgoyette 		bit = DBCOOL_CFG2_SHDN;
    850   1.1  pgoyette 	}
    851  1.13  christos 	cfg = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
    852  1.53       mrg 	if (suspend) {
    853  1.53       mrg 		sc->sc_suspend = (cfg & bit) != 0;
    854  1.53       mrg 		cfg |= bit;
    855  1.53       mrg 	} else {
    856  1.53       mrg 		cfg &= sc->sc_suspend ? bit : 0;
    857  1.53       mrg 	}
    858  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, reg, cfg);
    859   1.1  pgoyette 
    860   1.1  pgoyette 	return true;
    861   1.1  pgoyette }
    862   1.1  pgoyette 
    863  1.53       mrg bool
    864  1.53       mrg dbcool_pmf_suspend(device_t dev, const pmf_qual_t *qual)
    865   1.1  pgoyette {
    866   1.1  pgoyette 
    867  1.53       mrg 	return dbcool_do_pmf(dev, qual, true);
    868  1.53       mrg }
    869  1.45   msaitoh 
    870  1.53       mrg bool
    871  1.53       mrg dbcool_pmf_resume(device_t dev, const pmf_qual_t *qual)
    872  1.53       mrg {
    873   1.1  pgoyette 
    874  1.53       mrg 	return dbcool_do_pmf(dev, qual, false);
    875   1.1  pgoyette }
    876   1.1  pgoyette 
    877   1.1  pgoyette uint8_t
    878  1.13  christos dbcool_readreg(struct dbcool_chipset *dc, uint8_t reg)
    879   1.1  pgoyette {
    880   1.1  pgoyette 	uint8_t data = 0;
    881   1.1  pgoyette 
    882  1.13  christos 	if (iic_acquire_bus(dc->dc_tag, 0) != 0)
    883  1.11  pgoyette 		return data;
    884   1.1  pgoyette 
    885  1.16  pgoyette 	if (dc->dc_chip == NULL || dc->dc_chip->flags & DBCFLAG_NO_READBYTE) {
    886  1.10  pgoyette 		/* ADM1027 doesn't support i2c read_byte protocol */
    887  1.13  christos 		if (iic_smbus_send_byte(dc->dc_tag, dc->dc_addr, reg, 0) != 0)
    888  1.10  pgoyette 			goto bad;
    889  1.13  christos 		(void)iic_smbus_receive_byte(dc->dc_tag, dc->dc_addr, &data, 0);
    890  1.10  pgoyette 	} else
    891  1.13  christos 		(void)iic_smbus_read_byte(dc->dc_tag, dc->dc_addr, reg, &data,
    892  1.10  pgoyette 					  0);
    893   1.1  pgoyette 
    894   1.1  pgoyette bad:
    895  1.13  christos 	iic_release_bus(dc->dc_tag, 0);
    896   1.1  pgoyette 	return data;
    897   1.1  pgoyette }
    898   1.1  pgoyette 
    899  1.45   msaitoh void
    900  1.13  christos dbcool_writereg(struct dbcool_chipset *dc, uint8_t reg, uint8_t val)
    901   1.1  pgoyette {
    902  1.13  christos 	if (iic_acquire_bus(dc->dc_tag, 0) != 0)
    903   1.9  pgoyette 		return;
    904  1.45   msaitoh 
    905  1.13  christos 	(void)iic_smbus_write_byte(dc->dc_tag, dc->dc_addr, reg, val, 0);
    906   1.1  pgoyette 
    907  1.13  christos 	iic_release_bus(dc->dc_tag, 0);
    908  1.27  pgoyette }
    909   1.1  pgoyette 
    910   1.2  pgoyette static bool
    911   1.1  pgoyette dbcool_islocked(struct dbcool_softc *sc)
    912   1.1  pgoyette {
    913   1.1  pgoyette 	uint8_t cfg_reg;
    914   1.1  pgoyette 
    915  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
    916   1.1  pgoyette 		return 0;
    917   1.1  pgoyette 
    918  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466)
    919   1.1  pgoyette 		cfg_reg = DBCOOL_ADT7466_CONFIG1;
    920   1.1  pgoyette 	else
    921   1.1  pgoyette 		cfg_reg = DBCOOL_CONFIG1_REG;
    922   1.1  pgoyette 
    923  1.13  christos 	if (sc->sc_dc.dc_readreg(&sc->sc_dc, cfg_reg) & DBCOOL_CFG1_LOCK)
    924   1.1  pgoyette 		return 1;
    925   1.1  pgoyette 	else
    926   1.1  pgoyette 		return 0;
    927   1.1  pgoyette }
    928   1.1  pgoyette 
    929   1.1  pgoyette static int
    930   1.1  pgoyette dbcool_read_temp(struct dbcool_softc *sc, uint8_t reg, bool extres)
    931   1.1  pgoyette {
    932   1.1  pgoyette 	uint8_t	t1, t2, t3, val, ext = 0;
    933   1.1  pgoyette 	int temp;
    934   1.1  pgoyette 
    935  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) {
    936   1.1  pgoyette 		/*
    937   1.1  pgoyette 		 * ADT7466 temps are in strange location
    938   1.1  pgoyette 		 */
    939  1.13  christos 		ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADT7466_CONFIG1);
    940  1.13  christos 		val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
    941   1.1  pgoyette 		if (extres)
    942  1.13  christos 			ext = sc->sc_dc.dc_readreg(&sc->sc_dc, reg + 1);
    943  1.13  christos 	} else if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) {
    944   1.1  pgoyette 		/*
    945   1.1  pgoyette 		 * ADM1030 temps are in their own special place, too
    946   1.1  pgoyette 		 */
    947   1.1  pgoyette 		if (extres) {
    948  1.13  christos 			ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_TEMP_EXTRES);
    949   1.1  pgoyette 			if (reg == DBCOOL_ADM1030_L_TEMP)
    950   1.1  pgoyette 				ext >>= 6;
    951  1.22  macallan 			else if (reg == DBCOOL_ADM1031_R2_TEMP)
    952  1.22  macallan 				ext >>= 4;
    953   1.1  pgoyette 			else
    954   1.1  pgoyette 				ext >>= 1;
    955   1.1  pgoyette 			ext &= 0x03;
    956   1.1  pgoyette 		}
    957  1.13  christos 		val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
    958   1.2  pgoyette 	} else if (extres) {
    959  1.13  christos 		ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES2_REG);
    960   1.1  pgoyette 
    961   1.2  pgoyette 		/* Read all msb regs to unlatch them */
    962  1.13  christos 		t1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_12VIN);
    963  1.13  christos 		t1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_REMOTE1_TEMP);
    964  1.13  christos 		t2 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_REMOTE2_TEMP);
    965  1.13  christos 		t3 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_LOCAL_TEMP);
    966   1.2  pgoyette 		switch (reg) {
    967   1.2  pgoyette 		case DBCOOL_REMOTE1_TEMP:
    968   1.2  pgoyette 			val = t1;
    969   1.2  pgoyette 			ext >>= 2;
    970   1.2  pgoyette 			break;
    971   1.2  pgoyette 		case DBCOOL_LOCAL_TEMP:
    972   1.2  pgoyette 			val = t3;
    973   1.2  pgoyette 			ext >>= 4;
    974   1.2  pgoyette 			break;
    975   1.2  pgoyette 		case DBCOOL_REMOTE2_TEMP:
    976   1.2  pgoyette 			val = t2;
    977   1.2  pgoyette 			ext >>= 6;
    978   1.2  pgoyette 			break;
    979   1.2  pgoyette 		default:
    980   1.2  pgoyette 			val = 0;
    981   1.2  pgoyette 			break;
    982   1.1  pgoyette 		}
    983   1.2  pgoyette 		ext &= 0x03;
    984   1.1  pgoyette 	}
    985   1.2  pgoyette 	else
    986  1.13  christos 		val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
    987   1.1  pgoyette 
    988   1.1  pgoyette 	/* Check for invalid temp values */
    989   1.2  pgoyette 	if ((sc->sc_temp_offset == 0 && val == 0x80) ||
    990   1.2  pgoyette 	    (sc->sc_temp_offset != 0 && val == 0))
    991   1.1  pgoyette 		return 0;
    992   1.1  pgoyette 
    993   1.1  pgoyette 	/* If using offset mode, adjust, else treat as signed */
    994   1.2  pgoyette 	if (sc->sc_temp_offset) {
    995   1.1  pgoyette 		temp = val;
    996   1.2  pgoyette 		temp -= sc->sc_temp_offset;
    997   1.1  pgoyette 	} else
    998   1.1  pgoyette 		temp = (int8_t)val;
    999   1.1  pgoyette 
   1000   1.1  pgoyette 	/* Convert degC to uK and include extended precision bits */
   1001   1.1  pgoyette 	temp *= 1000000;
   1002   1.1  pgoyette 	temp +=  250000 * (int)ext;
   1003   1.1  pgoyette 	temp += 273150000U;
   1004   1.1  pgoyette 
   1005   1.1  pgoyette 	return temp;
   1006   1.1  pgoyette }
   1007   1.1  pgoyette 
   1008   1.1  pgoyette static int
   1009   1.1  pgoyette dbcool_read_rpm(struct dbcool_softc *sc, uint8_t reg)
   1010   1.1  pgoyette {
   1011   1.1  pgoyette 	int rpm;
   1012   1.1  pgoyette 	uint8_t rpm_lo, rpm_hi;
   1013   1.1  pgoyette 
   1014  1.13  christos 	rpm_lo = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
   1015  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
   1016   1.1  pgoyette 		rpm_hi = (rpm_lo == 0xff)?0xff:0x0;
   1017   1.1  pgoyette 	else
   1018  1.13  christos 		rpm_hi = sc->sc_dc.dc_readreg(&sc->sc_dc, reg + 1);
   1019   1.1  pgoyette 
   1020   1.1  pgoyette 	rpm = (rpm_hi << 8) | rpm_lo;
   1021   1.1  pgoyette 	if (rpm == 0xffff)
   1022   1.1  pgoyette 		return 0;	/* 0xffff indicates stalled/failed fan */
   1023   1.1  pgoyette 
   1024  1.23  macallan 	/* don't divide by zero */
   1025  1.23  macallan 	return (rpm == 0)? 0 : (sc->sc_dc.dc_chip->rpm_dividend / rpm);
   1026   1.1  pgoyette }
   1027   1.1  pgoyette 
   1028   1.2  pgoyette /* Provide chip's supply voltage, in microvolts */
   1029   1.1  pgoyette static int
   1030   1.1  pgoyette dbcool_supply_voltage(struct dbcool_softc *sc)
   1031   1.1  pgoyette {
   1032  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_MULTI_VCC) {
   1033  1.13  christos 		if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_CONFIG1_REG) & DBCOOL_CFG1_Vcc)
   1034   1.2  pgoyette 			return 5002500;
   1035   1.1  pgoyette 		else
   1036   1.2  pgoyette 			return 3300000;
   1037  1.13  christos 	} else if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) {
   1038  1.13  christos 		if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADT7466_CONFIG1) &
   1039   1.1  pgoyette 			    DBCOOL_ADT7466_CFG1_Vcc)
   1040   1.2  pgoyette 			return 5000000;
   1041   1.1  pgoyette 		else
   1042   1.2  pgoyette 			return 3300000;
   1043   1.1  pgoyette 	} else
   1044   1.2  pgoyette 		return 3300000;
   1045   1.1  pgoyette }
   1046   1.1  pgoyette 
   1047   1.2  pgoyette /*
   1048   1.2  pgoyette  * Nominal voltages are calculated in microvolts
   1049   1.2  pgoyette  */
   1050   1.1  pgoyette static int
   1051   1.2  pgoyette dbcool_read_volt(struct dbcool_softc *sc, uint8_t reg, int nom_idx, bool extres)
   1052   1.1  pgoyette {
   1053   1.1  pgoyette 	uint8_t ext = 0, v1, v2, v3, v4, val;
   1054   1.2  pgoyette 	int64_t ret;
   1055   1.2  pgoyette 	int64_t nom;
   1056   1.2  pgoyette 
   1057   1.2  pgoyette 	nom = nominal_voltages[nom_idx];
   1058   1.2  pgoyette 	if (nom < 0)
   1059   1.2  pgoyette 		nom = sc->sc_supply_voltage;
   1060   1.1  pgoyette 
   1061   1.1  pgoyette 	/* ADT7466 voltages are in strange locations with only 8-bits */
   1062  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466)
   1063  1.13  christos 		val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
   1064   1.2  pgoyette 	else
   1065   1.2  pgoyette 	/*
   1066   1.2  pgoyette 	 * It's a "normal" dbCool chip - check for regs that
   1067   1.2  pgoyette 	 * share extended resolution bits since we have to
   1068   1.2  pgoyette 	 * read all the MSB registers to unlatch them.
   1069   1.2  pgoyette 	 */
   1070   1.2  pgoyette 	if (!extres)
   1071  1.13  christos 		val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
   1072   1.2  pgoyette 	else if (reg == DBCOOL_12VIN) {
   1073  1.36       wiz 		ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES2_REG) & 0x03;
   1074  1.13  christos 		val = sc->sc_dc.dc_readreg(&sc->sc_dc, reg);
   1075   1.2  pgoyette 		(void)dbcool_read_temp(sc, DBCOOL_LOCAL_TEMP, true);
   1076   1.2  pgoyette 	} else if (reg == DBCOOL_VTT || reg == DBCOOL_IMON) {
   1077  1.13  christos 		ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES_VTT_IMON);
   1078  1.13  christos 		v1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_IMON);
   1079  1.13  christos 		v2 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_VTT);
   1080   1.2  pgoyette 		if (reg == DBCOOL_IMON) {
   1081   1.2  pgoyette 			val = v1;
   1082   1.2  pgoyette 			ext >>= 6;
   1083  1.48       mrg 		} else {
   1084   1.2  pgoyette 			val = v2;
   1085   1.2  pgoyette 			ext >>= 4;
   1086  1.48       mrg 		}
   1087   1.2  pgoyette 		ext &= 0x0f;
   1088   1.1  pgoyette 	} else {
   1089  1.13  christos 		ext = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_EXTRES1_REG);
   1090  1.13  christos 		v1 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_25VIN);
   1091  1.13  christos 		v2 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_VCCP);
   1092  1.13  christos 		v3 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_VCC);
   1093  1.13  christos 		v4 = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_5VIN);
   1094   1.1  pgoyette 
   1095   1.1  pgoyette 		switch (reg) {
   1096   1.1  pgoyette 		case DBCOOL_25VIN:
   1097   1.1  pgoyette 			val = v1;
   1098   1.1  pgoyette 			break;
   1099   1.2  pgoyette 		case DBCOOL_VCCP:
   1100   1.1  pgoyette 			val = v2;
   1101   1.1  pgoyette 			ext >>= 2;
   1102   1.1  pgoyette 			break;
   1103   1.2  pgoyette 		case DBCOOL_VCC:
   1104   1.1  pgoyette 			val = v3;
   1105   1.1  pgoyette 			ext >>= 4;
   1106   1.1  pgoyette 			break;
   1107   1.1  pgoyette 		case DBCOOL_5VIN:
   1108   1.1  pgoyette 			val = v4;
   1109   1.1  pgoyette 			ext >>= 6;
   1110   1.1  pgoyette 			break;
   1111   1.1  pgoyette 		default:
   1112   1.1  pgoyette 			val = nom = 0;
   1113   1.1  pgoyette 		}
   1114   1.1  pgoyette 		ext &= 0x03;
   1115   1.1  pgoyette 	}
   1116   1.1  pgoyette 
   1117  1.45   msaitoh 	/*
   1118   1.1  pgoyette 	 * Scale the nominal value by the 10-bit fraction
   1119   1.2  pgoyette 	 *
   1120   1.1  pgoyette 	 * Returned value is in microvolts.
   1121   1.1  pgoyette 	 */
   1122   1.2  pgoyette 	ret = val;
   1123   1.2  pgoyette 	ret <<= 2;
   1124   1.2  pgoyette 	ret |= ext;
   1125   1.1  pgoyette 	ret = (ret * nom) / 0x300;
   1126   1.1  pgoyette 
   1127   1.1  pgoyette 	return ret;
   1128   1.1  pgoyette }
   1129   1.1  pgoyette 
   1130   1.1  pgoyette static int
   1131   1.2  pgoyette sysctl_dbcool_temp(SYSCTLFN_ARGS)
   1132   1.1  pgoyette {
   1133   1.1  pgoyette 	struct sysctlnode node;
   1134   1.1  pgoyette 	struct dbcool_softc *sc;
   1135   1.1  pgoyette 	int reg, error;
   1136   1.1  pgoyette 	uint8_t chipreg;
   1137   1.1  pgoyette 	uint8_t newreg;
   1138   1.1  pgoyette 
   1139   1.1  pgoyette 	node = *rnode;
   1140   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1141   1.2  pgoyette 	chipreg = node.sysctl_num & 0xff;
   1142   1.1  pgoyette 
   1143   1.1  pgoyette 	if (sc->sc_temp_offset) {
   1144  1.13  christos 		reg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
   1145   1.1  pgoyette 		reg -= sc->sc_temp_offset;
   1146   1.1  pgoyette 	} else
   1147  1.13  christos 		reg = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
   1148   1.1  pgoyette 
   1149   1.1  pgoyette 	node.sysctl_data = &reg;
   1150   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1151   1.1  pgoyette 
   1152   1.1  pgoyette 	if (error || newp == NULL)
   1153   1.1  pgoyette 		return error;
   1154   1.1  pgoyette 
   1155  1.45   msaitoh 	/* We were asked to update the value - sanity check before writing */
   1156   1.1  pgoyette 	if (*(int *)node.sysctl_data < -64 ||
   1157   1.1  pgoyette 	    *(int *)node.sysctl_data > 127 + sc->sc_temp_offset)
   1158   1.1  pgoyette 		return EINVAL;
   1159   1.1  pgoyette 
   1160   1.1  pgoyette 	newreg = *(int *)node.sysctl_data;
   1161   1.1  pgoyette 	newreg += sc->sc_temp_offset;
   1162  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1163   1.1  pgoyette 	return 0;
   1164   1.1  pgoyette }
   1165   1.1  pgoyette 
   1166   1.1  pgoyette static int
   1167   1.2  pgoyette sysctl_adm1030_temp(SYSCTLFN_ARGS)
   1168   1.1  pgoyette {
   1169   1.1  pgoyette 	struct sysctlnode node;
   1170   1.1  pgoyette 	struct dbcool_softc *sc;
   1171   1.1  pgoyette 	int reg, error;
   1172   1.1  pgoyette 	uint8_t chipreg, oldreg, newreg;
   1173   1.1  pgoyette 
   1174   1.1  pgoyette 	node = *rnode;
   1175   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1176   1.2  pgoyette 	chipreg = node.sysctl_num & 0xff;
   1177   1.1  pgoyette 
   1178  1.13  christos 	oldreg = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
   1179   1.1  pgoyette 	reg = (oldreg >> 1) & ~0x03;
   1180   1.1  pgoyette 
   1181   1.1  pgoyette 	node.sysctl_data = &reg;
   1182   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1183   1.1  pgoyette 
   1184   1.1  pgoyette 	if (error || newp == NULL)
   1185   1.1  pgoyette 		return error;
   1186   1.1  pgoyette 
   1187  1.45   msaitoh 	/* We were asked to update the value - sanity check before writing */
   1188   1.1  pgoyette 	if (*(int *)node.sysctl_data < 0 || *(int *)node.sysctl_data > 127)
   1189   1.1  pgoyette 		return EINVAL;
   1190   1.1  pgoyette 
   1191   1.1  pgoyette 	newreg = *(int *)node.sysctl_data;
   1192   1.1  pgoyette 	newreg &= ~0x03;
   1193   1.1  pgoyette 	newreg <<= 1;
   1194   1.1  pgoyette 	newreg |= (oldreg & 0x07);
   1195  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1196   1.1  pgoyette 	return 0;
   1197   1.1  pgoyette }
   1198   1.1  pgoyette 
   1199   1.1  pgoyette static int
   1200   1.1  pgoyette sysctl_adm1030_trange(SYSCTLFN_ARGS)
   1201   1.1  pgoyette {
   1202   1.1  pgoyette 	struct sysctlnode node;
   1203   1.1  pgoyette 	struct dbcool_softc *sc;
   1204   1.1  pgoyette 	int reg, error, newval;
   1205   1.1  pgoyette 	uint8_t chipreg, oldreg, newreg;
   1206   1.1  pgoyette 
   1207   1.1  pgoyette 	node = *rnode;
   1208   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1209   1.2  pgoyette 	chipreg = node.sysctl_num & 0xff;
   1210   1.1  pgoyette 
   1211  1.13  christos 	oldreg = (int8_t)sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
   1212   1.1  pgoyette 	reg = oldreg & 0x07;
   1213   1.1  pgoyette 
   1214   1.1  pgoyette 	node.sysctl_data = &reg;
   1215   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1216   1.1  pgoyette 
   1217   1.1  pgoyette 	if (error || newp == NULL)
   1218   1.1  pgoyette 		return error;
   1219   1.1  pgoyette 
   1220  1.45   msaitoh 	/* We were asked to update the value - sanity check before writing */
   1221   1.1  pgoyette 	newval = *(int *)node.sysctl_data;
   1222   1.1  pgoyette 
   1223   1.1  pgoyette 	if (newval == 5)
   1224   1.1  pgoyette 		newreg = 0;
   1225   1.1  pgoyette 	else if (newval == 10)
   1226   1.1  pgoyette 		newreg = 1;
   1227   1.1  pgoyette 	else if (newval == 20)
   1228   1.1  pgoyette 		newreg = 2;
   1229   1.1  pgoyette 	else if (newval == 40)
   1230   1.1  pgoyette 		newreg = 3;
   1231   1.1  pgoyette 	else if (newval == 80)
   1232   1.1  pgoyette 		newreg = 4;
   1233   1.1  pgoyette 	else
   1234   1.1  pgoyette 		return EINVAL;
   1235   1.1  pgoyette 
   1236   1.1  pgoyette 	newreg |= (oldreg & ~0x07);
   1237  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1238   1.1  pgoyette 	return 0;
   1239   1.1  pgoyette }
   1240   1.1  pgoyette 
   1241   1.1  pgoyette static int
   1242   1.1  pgoyette sysctl_dbcool_duty(SYSCTLFN_ARGS)
   1243   1.1  pgoyette {
   1244   1.1  pgoyette 	struct sysctlnode node;
   1245   1.1  pgoyette 	struct dbcool_softc *sc;
   1246   1.1  pgoyette 	int reg, error;
   1247   1.1  pgoyette 	uint8_t chipreg, oldreg, newreg;
   1248   1.1  pgoyette 
   1249   1.1  pgoyette 	node = *rnode;
   1250   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1251   1.2  pgoyette 	chipreg = node.sysctl_num & 0xff;
   1252   1.1  pgoyette 
   1253  1.13  christos 	oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
   1254   1.1  pgoyette 	reg = (uint32_t)oldreg;
   1255  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
   1256   1.1  pgoyette 		reg = ((reg & 0x0f) * 100) / 15;
   1257   1.1  pgoyette 	else
   1258   1.1  pgoyette 		reg = (reg * 100) / 255;
   1259   1.1  pgoyette 	node.sysctl_data = &reg;
   1260   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1261   1.1  pgoyette 
   1262   1.1  pgoyette 	if (error || newp == NULL)
   1263   1.1  pgoyette 		return error;
   1264   1.1  pgoyette 
   1265  1.45   msaitoh 	/* We were asked to update the value - sanity check before writing */
   1266   1.1  pgoyette 	if (*(int *)node.sysctl_data < 0 || *(int *)node.sysctl_data > 100)
   1267   1.1  pgoyette 		return EINVAL;
   1268   1.1  pgoyette 
   1269  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) {
   1270   1.1  pgoyette 		newreg = *(uint8_t *)(node.sysctl_data) * 15 / 100;
   1271   1.1  pgoyette 		newreg |= oldreg & 0xf0;
   1272   1.1  pgoyette 	} else
   1273   1.1  pgoyette 		newreg = *(uint8_t *)(node.sysctl_data) * 255 / 100;
   1274  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1275   1.1  pgoyette 	return 0;
   1276   1.1  pgoyette }
   1277   1.1  pgoyette 
   1278   1.1  pgoyette static int
   1279   1.1  pgoyette sysctl_dbcool_behavior(SYSCTLFN_ARGS)
   1280   1.1  pgoyette {
   1281   1.1  pgoyette 	struct sysctlnode node;
   1282   1.1  pgoyette 	struct dbcool_softc *sc;
   1283   1.1  pgoyette 	int i, reg, error;
   1284   1.1  pgoyette 	uint8_t chipreg, oldreg, newreg;
   1285   1.1  pgoyette 
   1286   1.1  pgoyette 	node = *rnode;
   1287   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1288   1.2  pgoyette 	chipreg = node.sysctl_num & 0xff;
   1289  1.45   msaitoh 
   1290  1.13  christos 	oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
   1291   1.2  pgoyette 
   1292  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) {
   1293  1.13  christos 		if ((sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_CFG2) & 1) == 0)
   1294   1.1  pgoyette 			reg = 4;
   1295   1.1  pgoyette 		else if ((oldreg & 0x80) == 0)
   1296   1.1  pgoyette 			reg = 7;
   1297   1.1  pgoyette 		else if ((oldreg & 0x60) == 0)
   1298   1.1  pgoyette 			reg = 4;
   1299   1.1  pgoyette 		else
   1300   1.1  pgoyette 			reg = 6;
   1301   1.1  pgoyette 	} else
   1302   1.1  pgoyette 		reg = (oldreg >> 5) & 0x07;
   1303   1.1  pgoyette 
   1304   1.1  pgoyette 	strlcpy(dbcool_cur_behav, behavior[reg], sizeof(dbcool_cur_behav));
   1305   1.1  pgoyette 	node.sysctl_data = dbcool_cur_behav;
   1306   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1307   1.1  pgoyette 
   1308   1.1  pgoyette 	if (error || newp == NULL)
   1309   1.1  pgoyette 		return error;
   1310   1.1  pgoyette 
   1311   1.1  pgoyette 	/* We were asked to update the value - convert string to value */
   1312   1.1  pgoyette 	newreg = __arraycount(behavior);
   1313   1.1  pgoyette 	for (i = 0; i < __arraycount(behavior); i++)
   1314   1.1  pgoyette 		if (strcmp(node.sysctl_data, behavior[i]) == 0)
   1315   1.1  pgoyette 			break;
   1316   1.1  pgoyette 	if (i >= __arraycount(behavior))
   1317   1.1  pgoyette 		return EINVAL;
   1318  1.56  macallan 	newreg = i;
   1319  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) {
   1320   1.1  pgoyette 		/*
   1321   1.1  pgoyette 		 * ADM1030 splits fan controller behavior across two
   1322   1.1  pgoyette 		 * registers.  We also do not support Auto-Filter mode
   1323   1.1  pgoyette 		 * nor do we support Manual-RPM-feedback.
   1324   1.1  pgoyette 		 */
   1325   1.1  pgoyette 		if (newreg == 4) {
   1326  1.13  christos 			oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_CFG2);
   1327   1.1  pgoyette 			oldreg &= ~0x01;
   1328  1.13  christos 			sc->sc_dc.dc_writereg(&sc->sc_dc, DBCOOL_ADM1030_CFG2, oldreg);
   1329   1.1  pgoyette 		} else {
   1330   1.1  pgoyette 			if (newreg == 0)
   1331   1.1  pgoyette 				newreg = 4;
   1332   1.1  pgoyette 			else if (newreg == 6)
   1333   1.1  pgoyette 				newreg = 7;
   1334   1.1  pgoyette 			else if (newreg == 7)
   1335   1.1  pgoyette 				newreg = 0;
   1336   1.1  pgoyette 			else
   1337   1.1  pgoyette 				return EINVAL;
   1338   1.1  pgoyette 			newreg <<= 5;
   1339   1.1  pgoyette 			newreg |= (oldreg & 0x1f);
   1340  1.13  christos 			sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1341  1.13  christos 			oldreg = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADM1030_CFG2) | 1;
   1342  1.13  christos 			sc->sc_dc.dc_writereg(&sc->sc_dc, DBCOOL_ADM1030_CFG2, oldreg);
   1343   1.1  pgoyette 		}
   1344   1.1  pgoyette 	} else {
   1345  1.13  christos 		newreg = (sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg) & 0x1f) | (i << 5);
   1346  1.13  christos 		sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1347   1.1  pgoyette 	}
   1348   1.1  pgoyette 	return 0;
   1349   1.1  pgoyette }
   1350   1.1  pgoyette 
   1351   1.1  pgoyette static int
   1352   1.2  pgoyette sysctl_dbcool_slope(SYSCTLFN_ARGS)
   1353   1.1  pgoyette {
   1354   1.1  pgoyette 	struct sysctlnode node;
   1355   1.1  pgoyette 	struct dbcool_softc *sc;
   1356   1.1  pgoyette 	int reg, error;
   1357   1.1  pgoyette 	uint8_t chipreg;
   1358   1.1  pgoyette 	uint8_t newreg;
   1359   1.1  pgoyette 
   1360   1.1  pgoyette 	node = *rnode;
   1361   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1362   1.2  pgoyette 	chipreg = node.sysctl_num & 0xff;
   1363  1.45   msaitoh 
   1364  1.13  christos 	reg = (sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg) >> 4) & 0x0f;
   1365   1.1  pgoyette 	node.sysctl_data = &reg;
   1366   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1367   1.1  pgoyette 
   1368   1.1  pgoyette 	if (error || newp == NULL)
   1369   1.1  pgoyette 		return error;
   1370   1.1  pgoyette 
   1371  1.45   msaitoh 	/* We were asked to update the value - sanity check before writing */
   1372   1.1  pgoyette 	if (*(int *)node.sysctl_data < 0 || *(int *)node.sysctl_data > 0x0f)
   1373   1.1  pgoyette 		return EINVAL;
   1374   1.1  pgoyette 
   1375  1.13  christos 	newreg = (sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg) & 0x0f) |
   1376   1.1  pgoyette 		  (*(int *)node.sysctl_data << 4);
   1377  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1378   1.1  pgoyette 	return 0;
   1379   1.1  pgoyette }
   1380   1.1  pgoyette 
   1381   1.1  pgoyette static int
   1382   1.1  pgoyette sysctl_dbcool_thyst(SYSCTLFN_ARGS)
   1383   1.1  pgoyette {
   1384   1.1  pgoyette 	struct sysctlnode node;
   1385   1.1  pgoyette 	struct dbcool_softc *sc;
   1386   1.1  pgoyette 	int reg, error;
   1387   1.1  pgoyette 	uint8_t chipreg;
   1388   1.1  pgoyette 	uint8_t newreg, newhyst;
   1389   1.1  pgoyette 
   1390   1.1  pgoyette 	node = *rnode;
   1391   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1392   1.1  pgoyette 	chipreg = node.sysctl_num & 0x7f;
   1393   1.1  pgoyette 
   1394   1.1  pgoyette 	/* retrieve 4-bit value */
   1395  1.13  christos 	newreg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
   1396   1.1  pgoyette 	if ((node.sysctl_num & 0x80) == 0)
   1397   1.1  pgoyette 		reg = newreg >> 4;
   1398   1.1  pgoyette 	else
   1399   1.1  pgoyette 		reg = newreg;
   1400   1.1  pgoyette 	reg = reg & 0x0f;
   1401   1.1  pgoyette 
   1402   1.1  pgoyette 	node.sysctl_data = &reg;
   1403   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1404   1.1  pgoyette 
   1405   1.1  pgoyette 	if (error || newp == NULL)
   1406   1.1  pgoyette 		return error;
   1407   1.1  pgoyette 
   1408  1.45   msaitoh 	/* We were asked to update the value - sanity check before writing */
   1409   1.1  pgoyette 	newhyst = *(int *)node.sysctl_data;
   1410   1.1  pgoyette 	if (newhyst > 0x0f)
   1411   1.1  pgoyette 		return EINVAL;
   1412   1.1  pgoyette 
   1413   1.1  pgoyette 	/* Insert new value into field and update register */
   1414   1.1  pgoyette 	if ((node.sysctl_num & 0x80) == 0) {
   1415   1.1  pgoyette 		newreg &= 0x0f;
   1416   1.1  pgoyette 		newreg |= (newhyst << 4);
   1417   1.1  pgoyette 	} else {
   1418   1.1  pgoyette 		newreg &= 0xf0;
   1419   1.1  pgoyette 		newreg |= newhyst;
   1420   1.1  pgoyette 	}
   1421  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1422   1.1  pgoyette 	return 0;
   1423   1.1  pgoyette }
   1424   1.1  pgoyette 
   1425   1.1  pgoyette #ifdef DBCOOL_DEBUG
   1426   1.1  pgoyette 
   1427   1.1  pgoyette /*
   1428   1.1  pgoyette  * These routines can be used for debugging.  reg_select is used to
   1429   1.1  pgoyette  * select any arbitrary register in the device.  reg_access is used
   1430   1.1  pgoyette  * to read (and optionally update) the selected register.
   1431   1.1  pgoyette  *
   1432   1.1  pgoyette  * No attempt is made to validate the data passed.  If you use these
   1433   1.1  pgoyette  * routines, you are assumed to know what you're doing!
   1434   1.1  pgoyette  *
   1435   1.1  pgoyette  * Caveat user
   1436   1.1  pgoyette  */
   1437   1.1  pgoyette static int
   1438   1.1  pgoyette sysctl_dbcool_reg_select(SYSCTLFN_ARGS)
   1439   1.1  pgoyette {
   1440   1.1  pgoyette 	struct sysctlnode node;
   1441   1.1  pgoyette 	struct dbcool_softc *sc;
   1442   1.1  pgoyette 	int reg, error;
   1443   1.1  pgoyette 
   1444   1.1  pgoyette 	node = *rnode;
   1445   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1446  1.45   msaitoh 
   1447   1.1  pgoyette 	reg = sc->sc_user_reg;
   1448   1.1  pgoyette 	node.sysctl_data = &reg;
   1449   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1450   1.1  pgoyette 
   1451   1.1  pgoyette 	if (error || newp == NULL)
   1452   1.1  pgoyette 		return error;
   1453   1.1  pgoyette 
   1454   1.1  pgoyette 	sc->sc_user_reg = *(int *)node.sysctl_data;
   1455   1.1  pgoyette 	return 0;
   1456   1.1  pgoyette }
   1457   1.1  pgoyette 
   1458   1.1  pgoyette static int
   1459   1.1  pgoyette sysctl_dbcool_reg_access(SYSCTLFN_ARGS)
   1460   1.1  pgoyette {
   1461   1.1  pgoyette 	struct sysctlnode node;
   1462   1.1  pgoyette 	struct dbcool_softc *sc;
   1463   1.1  pgoyette 	int reg, error;
   1464   1.1  pgoyette 	uint8_t chipreg;
   1465   1.1  pgoyette 	uint8_t newreg;
   1466   1.1  pgoyette 
   1467   1.1  pgoyette 	node = *rnode;
   1468   1.1  pgoyette 	sc = (struct dbcool_softc *)node.sysctl_data;
   1469   1.1  pgoyette 	chipreg = sc->sc_user_reg;
   1470  1.45   msaitoh 
   1471  1.13  christos 	reg = sc->sc_dc.dc_readreg(&sc->sc_dc, chipreg);
   1472   1.1  pgoyette 	node.sysctl_data = &reg;
   1473   1.1  pgoyette 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   1474   1.1  pgoyette 
   1475   1.1  pgoyette 	if (error || newp == NULL)
   1476   1.1  pgoyette 		return error;
   1477   1.1  pgoyette 
   1478   1.1  pgoyette 	newreg = *(int *)node.sysctl_data;
   1479  1.13  christos 	sc->sc_dc.dc_writereg(&sc->sc_dc, chipreg, newreg);
   1480   1.1  pgoyette 	return 0;
   1481   1.1  pgoyette }
   1482   1.1  pgoyette #endif /* DBCOOL_DEBUG */
   1483   1.1  pgoyette 
   1484   1.1  pgoyette /*
   1485   1.2  pgoyette  * Encode an index number and register number for use as a sysctl_num
   1486   1.2  pgoyette  * so we can select the correct device register later.
   1487   1.1  pgoyette  */
   1488   1.2  pgoyette #define	DBC_PWM_SYSCTL(seq, reg)	((seq << 8) | reg)
   1489   1.1  pgoyette 
   1490   1.1  pgoyette void
   1491   1.1  pgoyette dbcool_setup(device_t self)
   1492   1.1  pgoyette {
   1493   1.1  pgoyette 	struct dbcool_softc *sc = device_private(self);
   1494   1.1  pgoyette 	const struct sysctlnode *me = NULL;
   1495  1.17  pgoyette #ifdef DBCOOL_DEBUG
   1496   1.1  pgoyette 	struct sysctlnode *node = NULL;
   1497  1.17  pgoyette #endif
   1498   1.1  pgoyette 	uint8_t cfg_val, cfg_reg;
   1499  1.18  pgoyette 	int ret, error;
   1500   1.1  pgoyette 
   1501   1.1  pgoyette 	/*
   1502   1.1  pgoyette 	 * Some chips are capable of reporting an extended temperature range
   1503   1.1  pgoyette 	 * by default.  On these models, config register 5 bit 0 can be set
   1504   1.1  pgoyette 	 * to 1 for compatability with other chips that report 2s complement.
   1505   1.1  pgoyette 	 */
   1506  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466) {
   1507  1.13  christos 		if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_ADT7466_CONFIG1) & 0x80)
   1508   1.1  pgoyette 			sc->sc_temp_offset = 64;
   1509   1.1  pgoyette 		else
   1510   1.1  pgoyette 			sc->sc_temp_offset = 0;
   1511  1.13  christos 	} else if (sc->sc_dc.dc_chip->flags & DBCFLAG_TEMPOFFSET) {
   1512  1.13  christos 		if (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_CONFIG5_REG) &
   1513   1.1  pgoyette 			    DBCOOL_CFG5_TWOSCOMP)
   1514   1.1  pgoyette 			sc->sc_temp_offset = 0;
   1515   1.1  pgoyette 		else
   1516   1.1  pgoyette 			sc->sc_temp_offset = 64;
   1517   1.1  pgoyette 	} else
   1518   1.1  pgoyette 		sc->sc_temp_offset = 0;
   1519   1.1  pgoyette 
   1520   1.2  pgoyette 	/* Determine Vcc for this chip */
   1521   1.2  pgoyette 	sc->sc_supply_voltage = dbcool_supply_voltage(sc);
   1522   1.2  pgoyette 
   1523  1.33  pgoyette 	ret = sysctl_createv(&sc->sc_sysctl_log, 0, NULL, &me,
   1524   1.2  pgoyette 	       CTLFLAG_READWRITE,
   1525   1.1  pgoyette 	       CTLTYPE_NODE, device_xname(self), NULL,
   1526   1.1  pgoyette 	       NULL, 0, NULL, 0,
   1527   1.1  pgoyette 	       CTL_HW, CTL_CREATE, CTL_EOL);
   1528  1.18  pgoyette 	if (ret == 0)
   1529  1.18  pgoyette 		sc->sc_root_sysctl_num = me->sysctl_num;
   1530  1.18  pgoyette 	else
   1531  1.18  pgoyette 		sc->sc_root_sysctl_num = 0;
   1532  1.18  pgoyette 
   1533  1.20  pgoyette 	aprint_debug_dev(self,
   1534  1.20  pgoyette 		"Supply voltage %"PRId64".%06"PRId64"V, %s temp range\n",
   1535  1.19  pgoyette 		sc->sc_supply_voltage / 1000000,
   1536  1.19  pgoyette 		sc->sc_supply_voltage % 1000000,
   1537  1.19  pgoyette 		sc->sc_temp_offset ? "extended" : "normal");
   1538  1.19  pgoyette 
   1539  1.18  pgoyette 	/* Create the sensors for this device */
   1540  1.18  pgoyette 	sc->sc_sme = sysmon_envsys_create();
   1541  1.18  pgoyette 	if (dbcool_setup_sensors(sc))
   1542  1.18  pgoyette 		goto out;
   1543  1.18  pgoyette 
   1544  1.18  pgoyette 	if (sc->sc_root_sysctl_num != 0) {
   1545  1.18  pgoyette 		/* If supported, create sysctl tree for fan PWM controllers */
   1546  1.18  pgoyette 		if (sc->sc_dc.dc_chip->power != NULL)
   1547  1.18  pgoyette 			dbcool_setup_controllers(sc);
   1548   1.1  pgoyette 
   1549   1.1  pgoyette #ifdef DBCOOL_DEBUG
   1550  1.33  pgoyette 		ret = sysctl_createv(&sc->sc_sysctl_log, 0, NULL,
   1551  1.34  christos 			(void *)&node,
   1552  1.18  pgoyette 			CTLFLAG_READWRITE, CTLTYPE_INT, "reg_select", NULL,
   1553  1.18  pgoyette 			sysctl_dbcool_reg_select,
   1554  1.38       dsl 			0, (void *)sc, sizeof(int),
   1555  1.18  pgoyette 			CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL);
   1556  1.18  pgoyette 		if (node != NULL)
   1557  1.18  pgoyette 			node->sysctl_data = sc;
   1558   1.1  pgoyette 
   1559  1.33  pgoyette 		ret = sysctl_createv(&sc->sc_sysctl_log, 0, NULL,
   1560  1.34  christos 			(void *)&node,
   1561  1.18  pgoyette 			CTLFLAG_READWRITE, CTLTYPE_INT, "reg_access", NULL,
   1562  1.18  pgoyette 			sysctl_dbcool_reg_access,
   1563  1.38       dsl 			0, (void *)sc, sizeof(int),
   1564  1.18  pgoyette 			CTL_HW, me->sysctl_num, CTL_CREATE, CTL_EOL);
   1565  1.18  pgoyette 		if (node != NULL)
   1566  1.18  pgoyette 			node->sysctl_data = sc;
   1567   1.1  pgoyette #endif /* DBCOOL_DEBUG */
   1568  1.18  pgoyette 	}
   1569   1.2  pgoyette 
   1570   1.2  pgoyette 	/*
   1571   1.2  pgoyette 	 * Read and rewrite config register to activate device
   1572   1.2  pgoyette 	 */
   1573  1.13  christos 	if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
   1574   1.2  pgoyette 		cfg_reg = DBCOOL_ADM1030_CFG1;
   1575  1.13  christos 	else if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADT7466)
   1576   1.2  pgoyette 		cfg_reg = DBCOOL_ADT7466_CONFIG1;
   1577   1.2  pgoyette 	else
   1578   1.2  pgoyette 		cfg_reg = DBCOOL_CONFIG1_REG;
   1579  1.13  christos 	cfg_val = sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_CONFIG1_REG);
   1580   1.2  pgoyette 	if ((cfg_val & DBCOOL_CFG1_START) == 0) {
   1581   1.2  pgoyette 		cfg_val |= DBCOOL_CFG1_START;
   1582  1.13  christos 		sc->sc_dc.dc_writereg(&sc->sc_dc, cfg_reg, cfg_val);
   1583   1.2  pgoyette 	}
   1584   1.2  pgoyette 	if (dbcool_islocked(sc))
   1585   1.2  pgoyette 		aprint_normal_dev(self, "configuration locked\n");
   1586   1.2  pgoyette 
   1587   1.2  pgoyette 	sc->sc_sme->sme_name = device_xname(self);
   1588   1.2  pgoyette 	sc->sc_sme->sme_cookie = sc;
   1589   1.2  pgoyette 	sc->sc_sme->sme_refresh = dbcool_refresh;
   1590  1.18  pgoyette 	sc->sc_sme->sme_set_limits = dbcool_set_limits;
   1591  1.18  pgoyette 	sc->sc_sme->sme_get_limits = dbcool_get_limits;
   1592   1.2  pgoyette 
   1593   1.2  pgoyette 	if ((error = sysmon_envsys_register(sc->sc_sme)) != 0) {
   1594   1.2  pgoyette 		aprint_error_dev(self,
   1595   1.2  pgoyette 		    "unable to register with sysmon (%d)\n", error);
   1596   1.2  pgoyette 		goto out;
   1597   1.2  pgoyette 	}
   1598  1.45   msaitoh 
   1599   1.2  pgoyette 	return;
   1600   1.2  pgoyette 
   1601   1.2  pgoyette out:
   1602   1.2  pgoyette 	sysmon_envsys_destroy(sc->sc_sme);
   1603   1.2  pgoyette }
   1604   1.2  pgoyette 
   1605   1.2  pgoyette static int
   1606  1.18  pgoyette dbcool_setup_sensors(struct dbcool_softc *sc)
   1607   1.2  pgoyette {
   1608  1.18  pgoyette 	int i;
   1609   1.2  pgoyette 	int error = 0;
   1610  1.18  pgoyette 	uint8_t	vid_reg, vid_val;
   1611  1.16  pgoyette 	struct chip_id *chip = sc->sc_dc.dc_chip;
   1612   1.2  pgoyette 
   1613  1.16  pgoyette 	for (i=0; chip->table[i].type != DBC_EOF; i++) {
   1614  1.18  pgoyette 		if (i < DBCOOL_MAXSENSORS)
   1615  1.18  pgoyette 			sc->sc_sysctl_num[i] = -1;
   1616  1.18  pgoyette 		else if (chip->table[i].type != DBC_CTL) {
   1617   1.2  pgoyette 			aprint_normal_dev(sc->sc_dev, "chip table too big!\n");
   1618   1.1  pgoyette 			break;
   1619   1.1  pgoyette 		}
   1620  1.16  pgoyette 		switch (chip->table[i].type) {
   1621   1.1  pgoyette 		case DBC_TEMP:
   1622   1.1  pgoyette 			sc->sc_sensor[i].units = ENVSYS_STEMP;
   1623  1.30  pgoyette 			sc->sc_sensor[i].state = ENVSYS_SINVALID;
   1624  1.16  pgoyette 			sc->sc_sensor[i].flags |= ENVSYS_FMONLIMITS;
   1625  1.41       tls 			sc->sc_sensor[i].flags |= ENVSYS_FHAS_ENTROPY;
   1626  1.18  pgoyette 			error = dbcool_attach_sensor(sc, i);
   1627   1.1  pgoyette 			break;
   1628   1.1  pgoyette 		case DBC_VOLT:
   1629  1.16  pgoyette 			/*
   1630  1.16  pgoyette 			 * If 12V-In pin has been reconfigured as 6th bit
   1631  1.16  pgoyette 			 * of VID code, don't create a 12V-In sensor
   1632  1.16  pgoyette 			 */
   1633  1.16  pgoyette 			if ((chip->flags & DBCFLAG_HAS_VID_SEL) &&
   1634  1.16  pgoyette 			    (chip->table[i].reg.val_reg == DBCOOL_12VIN) &&
   1635  1.16  pgoyette 			    (sc->sc_dc.dc_readreg(&sc->sc_dc, DBCOOL_VID_REG) &
   1636  1.16  pgoyette 					0x80))
   1637  1.16  pgoyette 				break;
   1638  1.16  pgoyette 
   1639   1.1  pgoyette 			sc->sc_sensor[i].units = ENVSYS_SVOLTS_DC;
   1640  1.30  pgoyette 			sc->sc_sensor[i].state = ENVSYS_SINVALID;
   1641  1.16  pgoyette 			sc->sc_sensor[i].flags |= ENVSYS_FMONLIMITS;
   1642  1.41       tls 			sc->sc_sensor[i].flags |= ENVSYS_FHAS_ENTROPY;
   1643  1.18  pgoyette 			error = dbcool_attach_sensor(sc, i);
   1644   1.1  pgoyette 			break;
   1645   1.1  pgoyette 		case DBC_FAN:
   1646   1.1  pgoyette 			sc->sc_sensor[i].units = ENVSYS_SFANRPM;
   1647  1.30  pgoyette 			sc->sc_sensor[i].state = ENVSYS_SINVALID;
   1648  1.16  pgoyette 			sc->sc_sensor[i].flags |= ENVSYS_FMONLIMITS;
   1649  1.41       tls 			sc->sc_sensor[i].flags |= ENVSYS_FHAS_ENTROPY;
   1650  1.18  pgoyette 			error = dbcool_attach_sensor(sc, i);
   1651   1.1  pgoyette 			break;
   1652  1.16  pgoyette 		case DBC_VID:
   1653  1.16  pgoyette 			sc->sc_sensor[i].units = ENVSYS_INTEGER;
   1654  1.30  pgoyette 			sc->sc_sensor[i].state = ENVSYS_SINVALID;
   1655  1.16  pgoyette 			sc->sc_sensor[i].flags |= ENVSYS_FMONNOTSUPP;
   1656  1.16  pgoyette 
   1657  1.16  pgoyette 			/* retrieve 5- or 6-bit value */
   1658  1.16  pgoyette 			vid_reg = chip->table[i].reg.val_reg;
   1659  1.16  pgoyette 			vid_val = sc->sc_dc.dc_readreg(&sc->sc_dc, vid_reg);
   1660  1.16  pgoyette 			if (chip->flags & DBCFLAG_HAS_VID_SEL)
   1661  1.16  pgoyette 				vid_val &= 0x3f;
   1662  1.16  pgoyette 			else
   1663  1.16  pgoyette 				vid_val &= 0x1f;
   1664  1.16  pgoyette 			sc->sc_sensor[i].value_cur = vid_val;
   1665  1.16  pgoyette 
   1666  1.18  pgoyette 			error = dbcool_attach_sensor(sc, i);
   1667  1.16  pgoyette 			break;
   1668   1.1  pgoyette 		case DBC_CTL:
   1669  1.18  pgoyette 			error = dbcool_attach_temp_control(sc, i, chip);
   1670  1.18  pgoyette 			if (error) {
   1671  1.18  pgoyette 				aprint_error_dev(sc->sc_dev,
   1672  1.18  pgoyette 						"attach index %d failed %d\n",
   1673  1.18  pgoyette 						i, error);
   1674  1.18  pgoyette 				error = 0;
   1675   1.1  pgoyette 			}
   1676   1.1  pgoyette 			break;
   1677   1.1  pgoyette 		default:
   1678   1.2  pgoyette 			aprint_error_dev(sc->sc_dev,
   1679   1.2  pgoyette 				"sensor_table index %d has bad type %d\n",
   1680  1.16  pgoyette 				i, chip->table[i].type);
   1681   1.1  pgoyette 			break;
   1682   1.1  pgoyette 		}
   1683   1.2  pgoyette 		if (error)
   1684   1.2  pgoyette 			break;
   1685   1.2  pgoyette 	}
   1686   1.2  pgoyette 	return error;
   1687   1.2  pgoyette }
   1688   1.1  pgoyette 
   1689   1.2  pgoyette static int
   1690  1.18  pgoyette dbcool_attach_sensor(struct dbcool_softc *sc, int idx)
   1691   1.2  pgoyette {
   1692   1.2  pgoyette 	int name_index;
   1693   1.2  pgoyette 	int error = 0;
   1694  1.55  macallan 	char name[8];
   1695  1.55  macallan 	const char *desc;
   1696   1.2  pgoyette 
   1697  1.13  christos 	name_index = sc->sc_dc.dc_chip->table[idx].name_index;
   1698  1.55  macallan 	snprintf(name, 7, "s%02x", sc->sc_dc.dc_chip->table[idx].reg.val_reg);
   1699  1.55  macallan 	if (prop_dictionary_get_cstring_nocopy(sc->sc_prop, name, &desc)) {
   1700  1.55  macallan 		 strlcpy(sc->sc_sensor[idx].desc, desc,
   1701  1.55  macallan 			sizeof(sc->sc_sensor[idx].desc));
   1702  1.55  macallan 	} else {
   1703  1.55  macallan 		strlcpy(sc->sc_sensor[idx].desc, dbc_sensor_names[name_index],
   1704  1.55  macallan 			sizeof(sc->sc_sensor[idx].desc));
   1705  1.55  macallan 	}
   1706  1.13  christos 	sc->sc_regs[idx] = &sc->sc_dc.dc_chip->table[idx].reg;
   1707  1.13  christos 	sc->sc_nom_volt[idx] = sc->sc_dc.dc_chip->table[idx].nom_volt_index;
   1708   1.2  pgoyette 
   1709   1.2  pgoyette 	error = sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[idx]);
   1710  1.18  pgoyette 	return error;
   1711  1.18  pgoyette }
   1712   1.2  pgoyette 
   1713  1.18  pgoyette static int
   1714  1.18  pgoyette dbcool_attach_temp_control(struct dbcool_softc *sc, int idx,
   1715  1.18  pgoyette 			   struct chip_id *chip)
   1716  1.18  pgoyette {
   1717  1.32  macallan 	const struct sysctlnode *me2 = NULL, *node;
   1718  1.18  pgoyette 	int j, ret, sysctl_index, rw_flag;
   1719  1.18  pgoyette 	uint8_t	sysctl_reg;
   1720  1.18  pgoyette 	char name[SYSCTL_NAMELEN];
   1721   1.2  pgoyette 
   1722  1.18  pgoyette 	/* Search for the corresponding temp sensor */
   1723  1.18  pgoyette 	for (j = 0; j < idx; j++) {
   1724  1.18  pgoyette 		if (j >= DBCOOL_MAXSENSORS || chip->table[j].type != DBC_TEMP)
   1725  1.18  pgoyette 			continue;
   1726  1.18  pgoyette 		if (chip->table[j].name_index == chip->table[idx].name_index)
   1727  1.18  pgoyette 			break;
   1728  1.18  pgoyette 	}
   1729  1.18  pgoyette 	if (j >= idx)	/* Temp sensor not found */
   1730  1.18  pgoyette 		return ENOENT;
   1731   1.1  pgoyette 
   1732  1.18  pgoyette 	/* create sysctl node for the sensor if not one already there */
   1733  1.18  pgoyette 	if (sc->sc_sysctl_num[j] == -1) {
   1734  1.55  macallan 		int name_index = sc->sc_dc.dc_chip->table[idx].name_index;
   1735  1.55  macallan 
   1736  1.33  pgoyette 		ret = sysctl_createv(&sc->sc_sysctl_log, 0, NULL, &me2,
   1737  1.33  pgoyette 				     CTLFLAG_READWRITE,
   1738  1.55  macallan 				     CTLTYPE_NODE, dbc_sensor_names[name_index],
   1739  1.55  macallan 				     sc->sc_sensor[j].desc,
   1740  1.18  pgoyette 				     NULL, 0, NULL, 0,
   1741  1.18  pgoyette 				     CTL_HW, sc->sc_root_sysctl_num, CTL_CREATE,
   1742  1.18  pgoyette 					CTL_EOL);
   1743  1.18  pgoyette 		if (me2 != NULL)
   1744  1.18  pgoyette 			sc->sc_sysctl_num[j] = me2->sysctl_num;
   1745  1.18  pgoyette 		else
   1746  1.18  pgoyette 			return ret;
   1747  1.18  pgoyette 	}
   1748  1.18  pgoyette 	/* add sysctl leaf node for this control variable */
   1749  1.18  pgoyette 	sysctl_index = chip->table[idx].sysctl_index;
   1750  1.18  pgoyette 	sysctl_reg = chip->table[idx].reg.val_reg;
   1751  1.18  pgoyette 	strlcpy(name, dbc_sysctl_table[sysctl_index].name, sizeof(name));
   1752  1.18  pgoyette 	if (dbc_sysctl_table[sysctl_index].lockable && dbcool_islocked(sc))
   1753  1.18  pgoyette 		rw_flag = CTLFLAG_READONLY | CTLFLAG_OWNDESC;
   1754  1.18  pgoyette 	else
   1755  1.18  pgoyette 		rw_flag = CTLFLAG_READWRITE | CTLFLAG_OWNDESC;
   1756  1.33  pgoyette 	ret = sysctl_createv(&sc->sc_sysctl_log, 0, NULL, &node, rw_flag,
   1757  1.18  pgoyette 			     CTLTYPE_INT, name,
   1758  1.25  pgoyette 			     SYSCTL_DESCR(dbc_sysctl_table[sysctl_index].desc),
   1759  1.18  pgoyette 			     dbc_sysctl_table[sysctl_index].helper,
   1760  1.38       dsl 			     0, (void *)sc, sizeof(int),
   1761  1.18  pgoyette 			     CTL_HW, sc->sc_root_sysctl_num,
   1762  1.18  pgoyette 				sc->sc_sysctl_num[j],
   1763  1.18  pgoyette 				DBC_PWM_SYSCTL(idx, sysctl_reg), CTL_EOL);
   1764   1.2  pgoyette 
   1765  1.18  pgoyette 	return ret;
   1766   1.2  pgoyette }
   1767   1.2  pgoyette 
   1768   1.2  pgoyette static void
   1769  1.18  pgoyette dbcool_setup_controllers(struct dbcool_softc *sc)
   1770   1.2  pgoyette {
   1771  1.39    martin 	int i, j, rw_flag;
   1772   1.2  pgoyette 	uint8_t sysctl_reg;
   1773  1.18  pgoyette 	struct chip_id *chip = sc->sc_dc.dc_chip;
   1774   1.2  pgoyette 	const struct sysctlnode *me2 = NULL;
   1775  1.32  macallan 	const struct sysctlnode *node = NULL;
   1776   1.2  pgoyette 	char name[SYSCTL_NAMELEN];
   1777   1.1  pgoyette 
   1778  1.18  pgoyette 	for (i = 0; chip->power[i].desc != NULL; i++) {
   1779   1.2  pgoyette 		snprintf(name, sizeof(name), "fan_ctl_%d", i);
   1780  1.39    martin 		sysctl_createv(&sc->sc_sysctl_log, 0, NULL, &me2,
   1781  1.18  pgoyette 		       CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
   1782   1.2  pgoyette 		       CTLTYPE_NODE, name, NULL,
   1783   1.2  pgoyette 		       NULL, 0, NULL, 0,
   1784  1.18  pgoyette 		       CTL_HW, sc->sc_root_sysctl_num, CTL_CREATE, CTL_EOL);
   1785   1.1  pgoyette 
   1786   1.2  pgoyette 		for (j = DBC_PWM_BEHAVIOR; j < DBC_PWM_LAST_PARAM; j++) {
   1787   1.2  pgoyette 			if (j == DBC_PWM_MAX_DUTY &&
   1788  1.18  pgoyette 			    (chip->flags & DBCFLAG_HAS_MAXDUTY) == 0)
   1789   1.2  pgoyette 				continue;
   1790  1.18  pgoyette 			sysctl_reg = chip->power[i].power_regs[j];
   1791   1.2  pgoyette 			if (sysctl_reg == DBCOOL_NO_REG)
   1792   1.2  pgoyette 				continue;
   1793   1.2  pgoyette 			strlcpy(name, dbc_sysctl_table[j].name, sizeof(name));
   1794  1.18  pgoyette 			if (dbc_sysctl_table[j].lockable && dbcool_islocked(sc))
   1795  1.18  pgoyette 				rw_flag = CTLFLAG_READONLY | CTLFLAG_OWNDESC;
   1796  1.18  pgoyette 			else
   1797  1.18  pgoyette 				rw_flag = CTLFLAG_READWRITE | CTLFLAG_OWNDESC;
   1798  1.39    martin 			(sysctl_createv)(&sc->sc_sysctl_log, 0, NULL,
   1799  1.32  macallan 				&node, rw_flag,
   1800   1.2  pgoyette 				(j == DBC_PWM_BEHAVIOR)?
   1801   1.2  pgoyette 					CTLTYPE_STRING:CTLTYPE_INT,
   1802   1.2  pgoyette 				name,
   1803  1.25  pgoyette 				SYSCTL_DESCR(dbc_sysctl_table[j].desc),
   1804   1.2  pgoyette 				dbc_sysctl_table[j].helper,
   1805  1.45   msaitoh 				0, sc,
   1806   1.2  pgoyette 				( j == DBC_PWM_BEHAVIOR)?
   1807   1.2  pgoyette 					sizeof(dbcool_cur_behav): sizeof(int),
   1808  1.18  pgoyette 				CTL_HW, sc->sc_root_sysctl_num, me2->sysctl_num,
   1809   1.2  pgoyette 				DBC_PWM_SYSCTL(j, sysctl_reg), CTL_EOL);
   1810   1.1  pgoyette 		}
   1811   1.1  pgoyette 	}
   1812   1.1  pgoyette }
   1813   1.1  pgoyette 
   1814   1.1  pgoyette static void
   1815   1.1  pgoyette dbcool_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
   1816   1.1  pgoyette {
   1817   1.1  pgoyette 	struct dbcool_softc *sc=sme->sme_cookie;
   1818  1.18  pgoyette 	int i, nom_volt_idx, cur;
   1819   1.1  pgoyette 	struct reg_list *reg;
   1820  1.45   msaitoh 
   1821   1.1  pgoyette 	i = edata->sensor;
   1822   1.1  pgoyette 	reg = sc->sc_regs[i];
   1823  1.45   msaitoh 
   1824  1.18  pgoyette 	edata->state = ENVSYS_SVALID;
   1825   1.1  pgoyette 	switch (edata->units)
   1826   1.1  pgoyette 	{
   1827   1.1  pgoyette 		case ENVSYS_STEMP:
   1828   1.1  pgoyette 			cur = dbcool_read_temp(sc, reg->val_reg, true);
   1829   1.1  pgoyette 			break;
   1830   1.1  pgoyette 		case ENVSYS_SVOLTS_DC:
   1831   1.2  pgoyette 			nom_volt_idx = sc->sc_nom_volt[i];
   1832   1.2  pgoyette 			cur = dbcool_read_volt(sc, reg->val_reg, nom_volt_idx,
   1833   1.2  pgoyette 						true);
   1834   1.1  pgoyette 			break;
   1835   1.1  pgoyette 		case ENVSYS_SFANRPM:
   1836   1.1  pgoyette 			cur = dbcool_read_rpm(sc, reg->val_reg);
   1837   1.1  pgoyette 			break;
   1838  1.16  pgoyette 		case ENVSYS_INTEGER:
   1839  1.16  pgoyette 			return;
   1840   1.1  pgoyette 		default:
   1841   1.1  pgoyette 			edata->state = ENVSYS_SINVALID;
   1842   1.1  pgoyette 			return;
   1843   1.1  pgoyette 	}
   1844   1.1  pgoyette 
   1845  1.18  pgoyette 	if (cur == 0 && (edata->units != ENVSYS_SFANRPM))
   1846   1.1  pgoyette 		edata->state = ENVSYS_SINVALID;
   1847   1.1  pgoyette 
   1848   1.1  pgoyette 	/*
   1849   1.1  pgoyette 	 * If fan is "stalled" but has no low limit, treat
   1850   1.1  pgoyette 	 * it as though the fan is not installed.
   1851   1.1  pgoyette 	 */
   1852   1.1  pgoyette 	else if (edata->units == ENVSYS_SFANRPM && cur == 0 &&
   1853  1.18  pgoyette 			!(edata->upropset & (PROP_CRITMIN | PROP_WARNMIN)))
   1854   1.1  pgoyette 		edata->state = ENVSYS_SINVALID;
   1855   1.1  pgoyette 
   1856   1.1  pgoyette 	edata->value_cur = cur;
   1857   1.1  pgoyette }
   1858   1.1  pgoyette 
   1859   1.1  pgoyette int
   1860  1.13  christos dbcool_chip_ident(struct dbcool_chipset *dc)
   1861   1.1  pgoyette {
   1862   1.1  pgoyette 	/* verify this is a supported dbCool chip */
   1863   1.1  pgoyette 	uint8_t c_id, d_id, r_id;
   1864   1.1  pgoyette 	int i;
   1865   1.1  pgoyette 
   1866  1.13  christos 	c_id = dc->dc_readreg(dc, DBCOOL_COMPANYID_REG);
   1867  1.13  christos 	d_id = dc->dc_readreg(dc, DBCOOL_DEVICEID_REG);
   1868  1.13  christos 	r_id = dc->dc_readreg(dc, DBCOOL_REVISION_REG);
   1869  1.27  pgoyette 
   1870  1.27  pgoyette 	/* The EMC6D103S only supports read_byte and since dc->dc_chip is
   1871  1.27  pgoyette 	 * NULL when we call dc->dc_readreg above we use
   1872  1.28  pgoyette 	 * send_byte/receive_byte which doesn't work.
   1873  1.27  pgoyette 	 *
   1874  1.27  pgoyette 	 * So if we only get 0's back then try again with dc->dc_chip
   1875  1.29  pgoyette 	 * set to the EMC6D103S_DEVICEID and which doesn't have
   1876  1.27  pgoyette 	 * DBCFLAG_NO_READBYTE set so read_byte will be used
   1877  1.27  pgoyette 	 */
   1878  1.27  pgoyette 	if ((c_id == 0) && (d_id == 0) && (r_id == 0)) {
   1879  1.27  pgoyette 		for (i = 0; chip_table[i].company != 0; i++)
   1880  1.27  pgoyette 			if ((SMSC_COMPANYID == chip_table[i].company) &&
   1881  1.27  pgoyette 			    (EMC6D103S_DEVICEID == chip_table[i].device)) {
   1882  1.27  pgoyette 				dc->dc_chip = &chip_table[i];
   1883  1.27  pgoyette 				break;
   1884  1.27  pgoyette 			}
   1885  1.27  pgoyette 		c_id = dc->dc_readreg(dc, DBCOOL_COMPANYID_REG);
   1886  1.27  pgoyette  		d_id = dc->dc_readreg(dc, DBCOOL_DEVICEID_REG);
   1887  1.27  pgoyette  		r_id = dc->dc_readreg(dc, DBCOOL_REVISION_REG);
   1888  1.27  pgoyette 	}
   1889  1.45   msaitoh 
   1890   1.1  pgoyette 	for (i = 0; chip_table[i].company != 0; i++)
   1891   1.1  pgoyette 		if ((c_id == chip_table[i].company) &&
   1892   1.1  pgoyette 		    (d_id == chip_table[i].device ||
   1893  1.13  christos 		    chip_table[i].device == 0xff) &&
   1894   1.1  pgoyette 		    (r_id == chip_table[i].rev ||
   1895  1.13  christos 		    chip_table[i].rev == 0xff)) {
   1896  1.13  christos 			dc->dc_chip = &chip_table[i];
   1897   1.1  pgoyette 			return i;
   1898   1.1  pgoyette 		}
   1899   1.1  pgoyette 
   1900  1.54    martin 	aprint_debug("dbcool_chip_ident: addr 0x%02x c_id 0x%02x d_id 0x%02x"
   1901  1.13  christos 			" r_id 0x%02x: No match.\n", dc->dc_addr, c_id, d_id,
   1902   1.1  pgoyette 			r_id);
   1903   1.1  pgoyette 
   1904   1.1  pgoyette 	return -1;
   1905  1.45   msaitoh }
   1906  1.18  pgoyette 
   1907  1.18  pgoyette /*
   1908  1.18  pgoyette  * Retrieve sensor limits from the chip registers
   1909  1.18  pgoyette  */
   1910  1.18  pgoyette static void
   1911  1.18  pgoyette dbcool_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
   1912  1.18  pgoyette 		  sysmon_envsys_lim_t *limits, uint32_t *props)
   1913  1.18  pgoyette {
   1914  1.18  pgoyette 	int index = edata->sensor;
   1915  1.18  pgoyette 	struct dbcool_softc *sc = sme->sme_cookie;
   1916  1.18  pgoyette 
   1917  1.19  pgoyette 	*props &= ~(PROP_CRITMIN | PROP_CRITMAX);
   1918  1.18  pgoyette 	switch (edata->units) {
   1919  1.18  pgoyette 	    case ENVSYS_STEMP:
   1920  1.18  pgoyette 		dbcool_get_temp_limits(sc, index, limits, props);
   1921  1.18  pgoyette 		break;
   1922  1.18  pgoyette 	    case ENVSYS_SVOLTS_DC:
   1923  1.18  pgoyette 		dbcool_get_volt_limits(sc, index, limits, props);
   1924  1.18  pgoyette 		break;
   1925  1.18  pgoyette 	    case ENVSYS_SFANRPM:
   1926  1.18  pgoyette 		dbcool_get_fan_limits(sc, index, limits, props);
   1927  1.18  pgoyette 
   1928  1.18  pgoyette 	    /* FALLTHROUGH */
   1929  1.18  pgoyette 	    default:
   1930  1.18  pgoyette 		break;
   1931  1.18  pgoyette 	}
   1932  1.18  pgoyette 	*props &= ~PROP_DRIVER_LIMITS;
   1933  1.19  pgoyette 
   1934  1.19  pgoyette 	/* If both limits provided, make sure they're sane */
   1935  1.19  pgoyette 	if ((*props & PROP_CRITMIN) &&
   1936  1.19  pgoyette 	    (*props & PROP_CRITMAX) &&
   1937  1.45   msaitoh 	    (limits->sel_critmin >= limits->sel_critmax))
   1938  1.19  pgoyette 		*props &= ~(PROP_CRITMIN | PROP_CRITMAX);
   1939  1.24  pgoyette 
   1940  1.24  pgoyette 	/*
   1941  1.24  pgoyette 	 * If this is the first time through, save these values
   1942  1.24  pgoyette 	 * in case user overrides them and then requests a reset.
   1943  1.24  pgoyette 	 */
   1944  1.24  pgoyette 	if (sc->sc_defprops[index] == 0) {
   1945  1.24  pgoyette 		sc->sc_defprops[index] = *props | PROP_DRIVER_LIMITS;
   1946  1.24  pgoyette 		sc->sc_deflims[index]  = *limits;
   1947  1.24  pgoyette 	}
   1948  1.18  pgoyette }
   1949  1.18  pgoyette 
   1950  1.18  pgoyette static void
   1951  1.18  pgoyette dbcool_get_temp_limits(struct dbcool_softc *sc, int idx,
   1952  1.18  pgoyette 		       sysmon_envsys_lim_t *lims, uint32_t *props)
   1953  1.18  pgoyette {
   1954  1.18  pgoyette 	struct reg_list *reg = sc->sc_regs[idx];
   1955  1.19  pgoyette 	uint8_t	lo_lim, hi_lim;
   1956  1.19  pgoyette 
   1957  1.19  pgoyette 	lo_lim = sc->sc_dc.dc_readreg(&sc->sc_dc, reg->lo_lim_reg);
   1958  1.19  pgoyette 	hi_lim = sc->sc_dc.dc_readreg(&sc->sc_dc, reg->hi_lim_reg);
   1959  1.18  pgoyette 
   1960  1.18  pgoyette 	if (sc->sc_temp_offset) {
   1961  1.19  pgoyette 		if (lo_lim > 0x01) {
   1962  1.19  pgoyette 			lims->sel_critmin = lo_lim - sc->sc_temp_offset;
   1963  1.19  pgoyette 			*props |= PROP_CRITMIN;
   1964  1.19  pgoyette 		}
   1965  1.19  pgoyette 		if (hi_lim != 0xff) {
   1966  1.19  pgoyette 			lims->sel_critmax = hi_lim - sc->sc_temp_offset;
   1967  1.19  pgoyette 			*props |= PROP_CRITMAX;
   1968  1.19  pgoyette 		}
   1969  1.19  pgoyette 	} else {
   1970  1.19  pgoyette 		if (lo_lim != 0x80 && lo_lim != 0x81) {
   1971  1.19  pgoyette 			lims->sel_critmin = (int8_t)lo_lim;
   1972  1.19  pgoyette 			*props |= PROP_CRITMIN;
   1973  1.19  pgoyette 		}
   1974  1.18  pgoyette 
   1975  1.19  pgoyette 		if (hi_lim != 0x7f) {
   1976  1.19  pgoyette 			lims->sel_critmax = (int8_t)hi_lim;
   1977  1.19  pgoyette 			*props |= PROP_CRITMAX;
   1978  1.19  pgoyette 		}
   1979  1.19  pgoyette 	}
   1980  1.18  pgoyette 
   1981  1.19  pgoyette 	/* Convert temp limits to microKelvin */
   1982  1.19  pgoyette 	lims->sel_critmin *= 1000000;
   1983  1.19  pgoyette 	lims->sel_critmin += 273150000;
   1984  1.19  pgoyette 	lims->sel_critmax *= 1000000;
   1985  1.19  pgoyette 	lims->sel_critmax += 273150000;
   1986  1.18  pgoyette }
   1987  1.18  pgoyette 
   1988  1.18  pgoyette static void
   1989  1.18  pgoyette dbcool_get_volt_limits(struct dbcool_softc *sc, int idx,
   1990  1.18  pgoyette 		       sysmon_envsys_lim_t *lims, uint32_t *props)
   1991  1.18  pgoyette {
   1992  1.18  pgoyette 	struct reg_list *reg = sc->sc_regs[idx];
   1993  1.18  pgoyette 	int64_t limit;
   1994  1.18  pgoyette 	int nom;
   1995  1.18  pgoyette 
   1996  1.18  pgoyette 	nom = nominal_voltages[sc->sc_dc.dc_chip->table[idx].nom_volt_index];
   1997  1.18  pgoyette 	if (nom < 0)
   1998  1.18  pgoyette 		nom = dbcool_supply_voltage(sc);
   1999  1.18  pgoyette 	nom *= 1000000;		/* scale for microvolts */
   2000  1.18  pgoyette 
   2001  1.18  pgoyette 	limit = sc->sc_dc.dc_readreg(&sc->sc_dc, reg->lo_lim_reg);
   2002  1.19  pgoyette 	if (limit != 0x00 && limit != 0xff) {
   2003  1.18  pgoyette 		limit *= nom;
   2004  1.18  pgoyette 		limit /= 0xc0;
   2005  1.18  pgoyette 		lims->sel_critmin = limit;
   2006  1.18  pgoyette 		*props |= PROP_CRITMIN;
   2007  1.18  pgoyette 	}
   2008  1.18  pgoyette 	limit = sc->sc_dc.dc_readreg(&sc->sc_dc, reg->hi_lim_reg);
   2009  1.19  pgoyette 	if (limit != 0x00 && limit != 0xff) {
   2010  1.18  pgoyette 		limit *= nom;
   2011  1.18  pgoyette 		limit /= 0xc0;
   2012  1.18  pgoyette 		lims->sel_critmax = limit;
   2013  1.18  pgoyette 		*props |= PROP_CRITMAX;
   2014  1.18  pgoyette 	}
   2015  1.18  pgoyette }
   2016  1.18  pgoyette 
   2017  1.18  pgoyette static void
   2018  1.18  pgoyette dbcool_get_fan_limits(struct dbcool_softc *sc, int idx,
   2019  1.18  pgoyette 		      sysmon_envsys_lim_t *lims, uint32_t *props)
   2020  1.18  pgoyette {
   2021  1.18  pgoyette 	struct reg_list *reg = sc->sc_regs[idx];
   2022  1.18  pgoyette 	int32_t	limit;
   2023  1.18  pgoyette 
   2024  1.18  pgoyette 	limit = dbcool_read_rpm(sc, reg->lo_lim_reg);
   2025  1.18  pgoyette 	if (limit) {
   2026  1.18  pgoyette 		lims->sel_critmin = limit;
   2027  1.18  pgoyette 		*props |= PROP_CRITMIN;
   2028  1.19  pgoyette 	}
   2029  1.18  pgoyette }
   2030  1.18  pgoyette 
   2031  1.18  pgoyette /*
   2032  1.18  pgoyette  * Update sensor limits in the chip registers
   2033  1.18  pgoyette  */
   2034  1.18  pgoyette static void
   2035  1.18  pgoyette dbcool_set_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
   2036  1.18  pgoyette 		  sysmon_envsys_lim_t *limits, uint32_t *props)
   2037  1.18  pgoyette {
   2038  1.18  pgoyette 	int index = edata->sensor;
   2039  1.18  pgoyette 	struct dbcool_softc *sc = sme->sme_cookie;
   2040  1.18  pgoyette 
   2041  1.24  pgoyette 	if (limits == NULL) {
   2042  1.24  pgoyette 		limits = &sc->sc_deflims[index];
   2043  1.24  pgoyette 		props  = &sc->sc_defprops[index];
   2044  1.24  pgoyette 	}
   2045  1.18  pgoyette 	switch (edata->units) {
   2046  1.18  pgoyette 	    case ENVSYS_STEMP:
   2047  1.18  pgoyette 		dbcool_set_temp_limits(sc, index, limits, props);
   2048  1.18  pgoyette 		break;
   2049  1.18  pgoyette 	    case ENVSYS_SVOLTS_DC:
   2050  1.18  pgoyette 		dbcool_set_volt_limits(sc, index, limits, props);
   2051  1.18  pgoyette 		break;
   2052  1.18  pgoyette 	    case ENVSYS_SFANRPM:
   2053  1.18  pgoyette 		dbcool_set_fan_limits(sc, index, limits, props);
   2054  1.18  pgoyette 
   2055  1.18  pgoyette 	    /* FALLTHROUGH */
   2056  1.18  pgoyette 	    default:
   2057  1.18  pgoyette 		break;
   2058  1.18  pgoyette 	}
   2059  1.18  pgoyette 	*props &= ~PROP_DRIVER_LIMITS;
   2060  1.18  pgoyette }
   2061  1.18  pgoyette 
   2062  1.18  pgoyette static void
   2063  1.18  pgoyette dbcool_set_temp_limits(struct dbcool_softc *sc, int idx,
   2064  1.18  pgoyette 		       sysmon_envsys_lim_t *lims, uint32_t *props)
   2065  1.18  pgoyette {
   2066  1.18  pgoyette 	struct reg_list *reg = sc->sc_regs[idx];
   2067  1.18  pgoyette 	int32_t	limit;
   2068  1.18  pgoyette 
   2069  1.18  pgoyette 	if (*props & PROP_CRITMIN) {
   2070  1.18  pgoyette 		limit = lims->sel_critmin - 273150000;
   2071  1.18  pgoyette 		limit /= 1000000;
   2072  1.19  pgoyette 		if (sc->sc_temp_offset) {
   2073  1.19  pgoyette 			limit += sc->sc_temp_offset;
   2074  1.19  pgoyette 			if (limit < 0)
   2075  1.19  pgoyette 				limit = 0;
   2076  1.19  pgoyette 			else if (limit > 255)
   2077  1.19  pgoyette 				limit = 255;
   2078  1.19  pgoyette 		} else {
   2079  1.19  pgoyette 			if (limit < -127)
   2080  1.19  pgoyette 				limit = -127;
   2081  1.19  pgoyette 			else if (limit > 127)
   2082  1.19  pgoyette 				limit = 127;
   2083  1.19  pgoyette 		}
   2084  1.24  pgoyette 		sc->sc_dc.dc_writereg(&sc->sc_dc, reg->lo_lim_reg,
   2085  1.24  pgoyette 				      (uint8_t)limit);
   2086  1.24  pgoyette 	} else if (*props & PROP_DRIVER_LIMITS) {
   2087  1.19  pgoyette 		if (sc->sc_temp_offset)
   2088  1.19  pgoyette 			limit = 0x00;
   2089  1.19  pgoyette 		else
   2090  1.19  pgoyette 			limit = 0x80;
   2091  1.24  pgoyette 		sc->sc_dc.dc_writereg(&sc->sc_dc, reg->lo_lim_reg,
   2092  1.24  pgoyette 				      (uint8_t)limit);
   2093  1.24  pgoyette 	}
   2094  1.18  pgoyette 
   2095  1.18  pgoyette 	if (*props & PROP_CRITMAX) {
   2096  1.18  pgoyette 		limit = lims->sel_critmax - 273150000;
   2097  1.18  pgoyette 		limit /= 1000000;
   2098  1.19  pgoyette 		if (sc->sc_temp_offset) {
   2099  1.19  pgoyette 			limit += sc->sc_temp_offset;
   2100  1.19  pgoyette 			if (limit < 0)
   2101  1.19  pgoyette 				limit = 0;
   2102  1.19  pgoyette 			else if (limit > 255)
   2103  1.19  pgoyette 				limit = 255;
   2104  1.19  pgoyette 		} else {
   2105  1.19  pgoyette 			if (limit < -127)
   2106  1.19  pgoyette 				limit = -127;
   2107  1.19  pgoyette 			else if (limit > 127)
   2108  1.19  pgoyette 				limit = 127;
   2109  1.19  pgoyette 		}
   2110  1.24  pgoyette 		sc->sc_dc.dc_writereg(&sc->sc_dc, reg->hi_lim_reg,
   2111  1.24  pgoyette 				      (uint8_t)limit);
   2112  1.24  pgoyette 	} else if (*props & PROP_DRIVER_LIMITS) {
   2113  1.19  pgoyette 		if (sc->sc_temp_offset)
   2114  1.18  pgoyette 			limit = 0xff;
   2115  1.19  pgoyette 		else
   2116  1.19  pgoyette 			limit = 0x7f;
   2117  1.24  pgoyette 		sc->sc_dc.dc_writereg(&sc->sc_dc, reg->hi_lim_reg,
   2118  1.24  pgoyette 				      (uint8_t)limit);
   2119  1.24  pgoyette 	}
   2120  1.18  pgoyette }
   2121  1.18  pgoyette 
   2122  1.18  pgoyette static void
   2123  1.18  pgoyette dbcool_set_volt_limits(struct dbcool_softc *sc, int idx,
   2124  1.18  pgoyette 		       sysmon_envsys_lim_t *lims, uint32_t *props)
   2125  1.18  pgoyette {
   2126  1.18  pgoyette 	struct reg_list *reg = sc->sc_regs[idx];
   2127  1.18  pgoyette 	int64_t limit;
   2128  1.18  pgoyette 	int nom;
   2129  1.18  pgoyette 
   2130  1.18  pgoyette 	nom = nominal_voltages[sc->sc_dc.dc_chip->table[idx].nom_volt_index];
   2131  1.18  pgoyette 	if (nom < 0)
   2132  1.18  pgoyette 		nom = dbcool_supply_voltage(sc);
   2133  1.18  pgoyette 	nom *= 1000000;		/* scale for microvolts */
   2134  1.18  pgoyette 
   2135  1.18  pgoyette 	if (*props & PROP_CRITMIN) {
   2136  1.18  pgoyette 		limit = lims->sel_critmin;
   2137  1.18  pgoyette 		limit *= 0xc0;
   2138  1.18  pgoyette 		limit /= nom;
   2139  1.18  pgoyette 		if (limit > 0xff)
   2140  1.18  pgoyette 			limit = 0xff;
   2141  1.18  pgoyette 		else if (limit < 0)
   2142  1.18  pgoyette 			limit = 0;
   2143  1.24  pgoyette 		sc->sc_dc.dc_writereg(&sc->sc_dc, reg->lo_lim_reg, limit);
   2144  1.24  pgoyette 	} else if (*props & PROP_DRIVER_LIMITS)
   2145  1.24  pgoyette 		sc->sc_dc.dc_writereg(&sc->sc_dc, reg->lo_lim_reg, 0);
   2146  1.18  pgoyette 
   2147  1.18  pgoyette 	if (*props & PROP_CRITMAX) {
   2148  1.18  pgoyette 		limit = lims->sel_critmax;
   2149  1.18  pgoyette 		limit *= 0xc0;
   2150  1.18  pgoyette 		limit /= nom;
   2151  1.18  pgoyette 		if (limit > 0xff)
   2152  1.18  pgoyette 			limit = 0xff;
   2153  1.18  pgoyette 		else if (limit < 0)
   2154  1.18  pgoyette 			limit = 0;
   2155  1.24  pgoyette 		sc->sc_dc.dc_writereg(&sc->sc_dc, reg->hi_lim_reg, limit);
   2156  1.24  pgoyette 	} else if (*props & PROP_DRIVER_LIMITS)
   2157  1.24  pgoyette 		sc->sc_dc.dc_writereg(&sc->sc_dc, reg->hi_lim_reg, 0xff);
   2158  1.18  pgoyette }
   2159  1.18  pgoyette 
   2160  1.18  pgoyette static void
   2161  1.18  pgoyette dbcool_set_fan_limits(struct dbcool_softc *sc, int idx,
   2162  1.18  pgoyette 		      sysmon_envsys_lim_t *lims, uint32_t *props)
   2163  1.18  pgoyette {
   2164  1.18  pgoyette 	struct reg_list *reg = sc->sc_regs[idx];
   2165  1.18  pgoyette 	int32_t	limit, dividend;
   2166  1.18  pgoyette 
   2167  1.18  pgoyette 	if (*props & PROP_CRITMIN) {
   2168  1.18  pgoyette 		limit = lims->sel_critmin;
   2169  1.18  pgoyette 		if (limit == 0)
   2170  1.18  pgoyette 			limit = 0xffff;
   2171  1.18  pgoyette 		else {
   2172  1.18  pgoyette 			if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030)
   2173  1.18  pgoyette 				dividend = 11250 * 60;
   2174  1.18  pgoyette 			else
   2175  1.18  pgoyette 				dividend = 90000 * 60;
   2176  1.18  pgoyette 			limit = limit / dividend;
   2177  1.18  pgoyette 			if (limit > 0xffff)
   2178  1.18  pgoyette 				limit = 0xffff;
   2179  1.18  pgoyette 		}
   2180  1.24  pgoyette 		sc->sc_dc.dc_writereg(&sc->sc_dc, reg->lo_lim_reg,
   2181  1.24  pgoyette 				      limit & 0xff);
   2182  1.24  pgoyette 		limit >>= 8;
   2183  1.24  pgoyette 		sc->sc_dc.dc_writereg(&sc->sc_dc, reg->lo_lim_reg + 1,
   2184  1.24  pgoyette 				      limit & 0xff);
   2185  1.24  pgoyette 	} else if (*props & PROP_DRIVER_LIMITS) {
   2186  1.24  pgoyette 		sc->sc_dc.dc_writereg(&sc->sc_dc, reg->lo_lim_reg, 0xff);
   2187  1.24  pgoyette 		sc->sc_dc.dc_writereg(&sc->sc_dc, reg->lo_lim_reg + 1, 0xff);
   2188  1.24  pgoyette 	}
   2189  1.18  pgoyette }
   2190  1.31  jmcneill 
   2191  1.43  pgoyette MODULE(MODULE_CLASS_DRIVER, dbcool, "i2cexec,sysmon_envsys");
   2192  1.31  jmcneill 
   2193  1.31  jmcneill #ifdef _MODULE
   2194  1.31  jmcneill #include "ioconf.c"
   2195  1.31  jmcneill #endif
   2196  1.31  jmcneill 
   2197  1.31  jmcneill static int
   2198  1.31  jmcneill dbcool_modcmd(modcmd_t cmd, void *opaque)
   2199  1.31  jmcneill {
   2200  1.31  jmcneill 	int error = 0;
   2201  1.37  pgoyette #ifdef _MODULE
   2202  1.37  pgoyette 	static struct sysctllog *dbcool_sysctl_clog;
   2203  1.37  pgoyette #endif
   2204  1.31  jmcneill 
   2205  1.31  jmcneill 	switch (cmd) {
   2206  1.31  jmcneill 	case MODULE_CMD_INIT:
   2207  1.31  jmcneill #ifdef _MODULE
   2208  1.31  jmcneill 		error = config_init_component(cfdriver_ioconf_dbcool,
   2209  1.31  jmcneill 		    cfattach_ioconf_dbcool, cfdata_ioconf_dbcool);
   2210  1.37  pgoyette 		sysctl_dbcoolsetup(&dbcool_sysctl_clog);
   2211  1.31  jmcneill #endif
   2212  1.31  jmcneill 		return error;
   2213  1.31  jmcneill 	case MODULE_CMD_FINI:
   2214  1.31  jmcneill #ifdef _MODULE
   2215  1.31  jmcneill 		error = config_fini_component(cfdriver_ioconf_dbcool,
   2216  1.31  jmcneill 		    cfattach_ioconf_dbcool, cfdata_ioconf_dbcool);
   2217  1.37  pgoyette 		sysctl_teardown(&dbcool_sysctl_clog);
   2218  1.31  jmcneill #endif
   2219  1.31  jmcneill 		return error;
   2220  1.31  jmcneill 	default:
   2221  1.31  jmcneill 		return ENOTTY;
   2222  1.31  jmcneill 	}
   2223  1.31  jmcneill }
   2224