From 9232f4eb43d7b8b00f460d1dc93e6d1db0938cd1 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 9 May 2007 13:00:30 +0000 Subject: [PATCH] Delete all kernel chip drivers, documentation and references. We are moving to a user-space-only package, all the drivers are maintained in the Linux kernel tree itself. I tried to update the documentation a bit, but there's still a lot to go. In fact, a complete rewrite seems to be needed. git-svn-id: http://lm-sensors.org/svn/lm-sensors/branches/lm-sensors-3.0.0@4397 7894878c-1315-0410-8ee3-d5d059ff63e0 --- CHANGES | 1 + Makefile | 189 +-- QUICKSTART | 54 +- README.directories | 4 +- doc/chips/adm1021 | 415 ----- doc/chips/adm1024 | 12 - doc/chips/adm1025 | 135 -- doc/chips/adm1026 | 217 --- doc/chips/adm1031 | 109 -- doc/chips/adm9240 | 424 ------ doc/chips/asb100 | 89 -- doc/chips/bmcsensors | 140 -- doc/chips/bt869 | 397 ----- doc/chips/ddcmon | 272 ---- doc/chips/ds1307 | 25 - doc/chips/ds1621 | 237 --- doc/chips/eeprom | 228 --- doc/chips/f71805f | 107 -- doc/chips/fscher | 266 ---- doc/chips/fscpos | 122 -- doc/chips/fscscy | 251 --- doc/chips/gl518sm | 184 --- doc/chips/gl520sm | 146 -- doc/chips/it87 | 273 ---- doc/chips/lm63 | 102 -- doc/chips/lm75 | 107 -- doc/chips/lm78 | 337 ----- doc/chips/lm80 | 149 -- doc/chips/lm83 | 156 -- doc/chips/lm85 | 527 ------- doc/chips/lm87 | 150 -- doc/chips/lm90 | 223 --- doc/chips/lm92 | 89 -- doc/chips/lm93 | 386 ----- doc/chips/ltc1710 | 67 - doc/chips/matorb | 97 -- doc/chips/max1619 | 73 - doc/chips/max6650 | 125 -- doc/chips/maxilife | 433 ------ doc/chips/mic74 | 57 - doc/chips/mtp008 | 73 - doc/chips/pc87360 | 184 --- doc/chips/pca9540 | 76 - doc/chips/pcf8574 | 100 -- doc/chips/pcf8591 | 127 -- doc/chips/saa1064 | 81 - doc/chips/sis5595 | 165 -- doc/chips/smartbatt | 66 - doc/chips/smbus-arp | 66 - doc/chips/smsc47m1 | 75 - doc/chips/thmc50 | 96 -- doc/chips/via686a | 155 -- doc/chips/vt1211 | 70 - doc/chips/vt8231 | 184 --- doc/chips/w83627hf | 103 -- doc/chips/w83781d | 799 ---------- doc/chips/w83792d | 298 ---- doc/chips/w83l785ts | 77 - doc/chips/xeontemp | 108 -- doc/developers/design | 550 ------- doc/developers/makefiles | 20 +- doc/developers/new_drivers | 166 -- doc/developers/proc | 145 -- doc/developers/release_checklist | 12 +- doc/developers/sysctl | 16 - doc/kernel/file_operations | 91 -- doc/kernel/proc_dir_entry | 145 -- doc/modules | 14 - etc/sensors.conf.eg | 10 +- kernel/Module.mk | 42 - kernel/chips/Module.mk | 210 --- kernel/chips/adm1021.c | 587 -------- kernel/chips/adm1024.c | 776 ---------- kernel/chips/adm1025.c | 588 -------- kernel/chips/adm1026.c | 1741 --------------------- kernel/chips/adm1031.c | 643 -------- kernel/chips/adm9240.c | 700 --------- kernel/chips/asb100.c | 1017 ------------- kernel/chips/bmcsensors.c | 1133 -------------- kernel/chips/bt869.c | 886 ----------- kernel/chips/ddcmon.c | 586 -------- kernel/chips/ds1307.c | 345 ----- kernel/chips/ds1621.c | 537 ------- kernel/chips/eeprom.c | 370 ----- kernel/chips/f71805f.c | 757 ---------- kernel/chips/fscher.c | 729 --------- kernel/chips/fscpos.c | 684 --------- kernel/chips/fscscy.c | 909 ----------- kernel/chips/gl518sm.c | 987 ------------ kernel/chips/gl520sm.c | 804 ---------- kernel/chips/it87.c | 1130 -------------- kernel/chips/lm63.c | 645 -------- kernel/chips/lm75.c | 330 ---- kernel/chips/lm75.h | 49 - kernel/chips/lm78.c | 721 --------- kernel/chips/lm80.c | 599 -------- kernel/chips/lm83.c | 528 ------- kernel/chips/lm85.c | 2037 ------------------------- kernel/chips/lm87.c | 982 ------------ kernel/chips/lm90.c | 858 ----------- kernel/chips/lm92.c | 416 ----- kernel/chips/lm93.c | 2343 ----------------------------- kernel/chips/lm93.h | 113 -- kernel/chips/ltc1710.c | 313 ---- kernel/chips/matorb.c | 281 ---- kernel/chips/max1619.c | 491 ------ kernel/chips/max6650.c | 537 ------- kernel/chips/maxilife.c | 1379 ----------------- kernel/chips/mic74.c | 378 ----- kernel/chips/mtp008.c | 1098 -------------- kernel/chips/pc87360.c | 1350 ----------------- kernel/chips/pca9540.c | 241 --- kernel/chips/pcf8574.c | 304 ---- kernel/chips/pcf8591.c | 443 ------ kernel/chips/saa1064.c | 427 ------ kernel/chips/sis5595.c | 721 --------- kernel/chips/smartbatt.c | 546 ------- kernel/chips/smbus-arp.c | 478 ------ kernel/chips/smsc47m1.c | 603 -------- kernel/chips/thmc50.c | 491 ------ kernel/chips/via686a.c | 840 ----------- kernel/chips/vt1211.c | 820 ---------- kernel/chips/vt8231.c | 836 ---------- kernel/chips/w83627hf.c | 1501 ------------------ kernel/chips/w83781d.c | 1883 ----------------------- kernel/chips/w83792d.c | 1532 ------------------- kernel/chips/w83l785ts.c | 379 ----- kernel/chips/xeontemp.c | 383 ----- kernel/include/Module.mk | 18 - kernel/include/ds1307.h | 59 - kernel/include/sensors.h | 1608 ++++++++++++++++++++ kernel/include/sensors.h.template | 55 - kernel/include/sensors_compat.h | 51 - kernel/include/sensors_vid.h | 98 -- kernel/sensors.c | 20 - lm_sensors.lsm | 7 +- 136 files changed, 1633 insertions(+), 55767 deletions(-) delete mode 100644 doc/chips/adm1021 delete mode 100644 doc/chips/adm1024 delete mode 100644 doc/chips/adm1025 delete mode 100644 doc/chips/adm1026 delete mode 100644 doc/chips/adm1031 delete mode 100644 doc/chips/adm9240 delete mode 100644 doc/chips/asb100 delete mode 100644 doc/chips/bmcsensors delete mode 100644 doc/chips/bt869 delete mode 100644 doc/chips/ddcmon delete mode 100644 doc/chips/ds1307 delete mode 100644 doc/chips/ds1621 delete mode 100644 doc/chips/eeprom delete mode 100644 doc/chips/f71805f delete mode 100644 doc/chips/fscher delete mode 100644 doc/chips/fscpos delete mode 100644 doc/chips/fscscy delete mode 100644 doc/chips/gl518sm delete mode 100644 doc/chips/gl520sm delete mode 100644 doc/chips/it87 delete mode 100644 doc/chips/lm63 delete mode 100644 doc/chips/lm75 delete mode 100644 doc/chips/lm78 delete mode 100644 doc/chips/lm80 delete mode 100644 doc/chips/lm83 delete mode 100644 doc/chips/lm85 delete mode 100644 doc/chips/lm87 delete mode 100644 doc/chips/lm90 delete mode 100644 doc/chips/lm92 delete mode 100644 doc/chips/lm93 delete mode 100644 doc/chips/ltc1710 delete mode 100644 doc/chips/matorb delete mode 100644 doc/chips/max1619 delete mode 100644 doc/chips/max6650 delete mode 100644 doc/chips/maxilife delete mode 100644 doc/chips/mic74 delete mode 100644 doc/chips/mtp008 delete mode 100644 doc/chips/pc87360 delete mode 100644 doc/chips/pca9540 delete mode 100644 doc/chips/pcf8574 delete mode 100644 doc/chips/pcf8591 delete mode 100644 doc/chips/saa1064 delete mode 100644 doc/chips/sis5595 delete mode 100644 doc/chips/smartbatt delete mode 100644 doc/chips/smbus-arp delete mode 100644 doc/chips/smsc47m1 delete mode 100644 doc/chips/thmc50 delete mode 100644 doc/chips/via686a delete mode 100644 doc/chips/vt1211 delete mode 100644 doc/chips/vt8231 delete mode 100644 doc/chips/w83627hf delete mode 100644 doc/chips/w83781d delete mode 100644 doc/chips/w83792d delete mode 100644 doc/chips/w83l785ts delete mode 100644 doc/chips/xeontemp delete mode 100644 doc/developers/design delete mode 100644 doc/developers/new_drivers delete mode 100644 doc/developers/proc delete mode 100644 doc/developers/sysctl delete mode 100644 doc/kernel/file_operations delete mode 100644 doc/kernel/proc_dir_entry delete mode 100644 doc/modules delete mode 100644 kernel/Module.mk delete mode 100644 kernel/chips/Module.mk delete mode 100644 kernel/chips/adm1021.c delete mode 100644 kernel/chips/adm1024.c delete mode 100644 kernel/chips/adm1025.c delete mode 100644 kernel/chips/adm1026.c delete mode 100644 kernel/chips/adm1031.c delete mode 100644 kernel/chips/adm9240.c delete mode 100644 kernel/chips/asb100.c delete mode 100644 kernel/chips/bmcsensors.c delete mode 100644 kernel/chips/bt869.c delete mode 100644 kernel/chips/ddcmon.c delete mode 100644 kernel/chips/ds1307.c delete mode 100644 kernel/chips/ds1621.c delete mode 100644 kernel/chips/eeprom.c delete mode 100644 kernel/chips/f71805f.c delete mode 100644 kernel/chips/fscher.c delete mode 100644 kernel/chips/fscpos.c delete mode 100644 kernel/chips/fscscy.c delete mode 100644 kernel/chips/gl518sm.c delete mode 100644 kernel/chips/gl520sm.c delete mode 100644 kernel/chips/it87.c delete mode 100644 kernel/chips/lm63.c delete mode 100644 kernel/chips/lm75.c delete mode 100644 kernel/chips/lm75.h delete mode 100644 kernel/chips/lm78.c delete mode 100644 kernel/chips/lm80.c delete mode 100644 kernel/chips/lm83.c delete mode 100644 kernel/chips/lm85.c delete mode 100644 kernel/chips/lm87.c delete mode 100644 kernel/chips/lm90.c delete mode 100644 kernel/chips/lm92.c delete mode 100644 kernel/chips/lm93.c delete mode 100644 kernel/chips/lm93.h delete mode 100644 kernel/chips/ltc1710.c delete mode 100644 kernel/chips/matorb.c delete mode 100644 kernel/chips/max1619.c delete mode 100644 kernel/chips/max6650.c delete mode 100644 kernel/chips/maxilife.c delete mode 100644 kernel/chips/mic74.c delete mode 100644 kernel/chips/mtp008.c delete mode 100644 kernel/chips/pc87360.c delete mode 100644 kernel/chips/pca9540.c delete mode 100644 kernel/chips/pcf8574.c delete mode 100644 kernel/chips/pcf8591.c delete mode 100644 kernel/chips/saa1064.c delete mode 100644 kernel/chips/sis5595.c delete mode 100644 kernel/chips/smartbatt.c delete mode 100644 kernel/chips/smbus-arp.c delete mode 100644 kernel/chips/smsc47m1.c delete mode 100644 kernel/chips/thmc50.c delete mode 100644 kernel/chips/via686a.c delete mode 100644 kernel/chips/vt1211.c delete mode 100644 kernel/chips/vt8231.c delete mode 100644 kernel/chips/w83627hf.c delete mode 100644 kernel/chips/w83781d.c delete mode 100644 kernel/chips/w83792d.c delete mode 100644 kernel/chips/w83l785ts.c delete mode 100644 kernel/chips/xeontemp.c delete mode 100644 kernel/include/ds1307.h create mode 100644 kernel/include/sensors.h delete mode 100644 kernel/include/sensors.h.template delete mode 100644 kernel/include/sensors_compat.h delete mode 100644 kernel/include/sensors_vid.h delete mode 100644 kernel/sensors.c diff --git a/CHANGES b/CHANGES index 065109f0..46c4d34f 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,7 @@ lm_sensors CHANGES file SVN HEAD All bus modules and documentation: Delete + All chip modules and documentation: Delete File doc/version-2: Delete, obsolete File sensors.conf.eg: Add a dme1737 section File lm_sensors.sysconfig: Delete, now generated by sensors-detect diff --git a/Makefile b/Makefile index eeb8af9c..61a5b39e 100644 --- a/Makefile +++ b/Makefile @@ -27,38 +27,6 @@ # I think so, but I have not tested it. #SHELL := /usr/bin/bash -# The currently running kernel version. This is used right below to -# determine where the kernel sources can be found. -KERNELVERSION := $(shell uname -r) - -# The location of linux itself. This is used to find the kernel headers -# and other things. -#LINUX := /usr/src/linux -LINUX := $(shell if [ -L "/lib/modules/$(KERNELVERSION)/build" ] ; \ - then echo "/lib/modules/$(KERNELVERSION)/build" ; \ - else echo "/usr/src/linux" ; fi) -LINUX_HEADERS := $(LINUX)/include - -# If you have installed the i2c header at some other place (like -# /usr/local/include/linux), set that directory here. Please check this out -# if you get strange compilation errors; the default Linux i2c headers -# may be used mistakenly. Note: This should point to the directory -# *above* the linux/ subdirectory, so to /usr/local/include in the -# above example. -I2C_HEADERS := /usr/local/include -#I2C_HEADERS := $(LINUX_HEADERS) - -ifneq ($(MAKECMDGOALS),user) -ifneq ($(MAKECMDGOALS),user_install) -ifneq ($(MAKECMDGOALS),user_uninstall) -SMP := $(shell if grep -q '^[[:space:]]*\#define[[:space:]]*CONFIG_SMP[[:space:]]*1' $(LINUX_HEADERS)/linux/autoconf.h ; \ - then echo 1; else echo 0; fi) -MODVER := $(shell if grep -q '^[[:space:]]*\#define[[:space:]]*CONFIG_MODVERSIONS[[:space:]]*1' $(LINUX_HEADERS)/linux/autoconf.h ; \ - then echo 1; else echo 0; fi) -endif -endif -endif - # Uncomment the second line if you are a developer. This will enable many # additional warnings at compile-time WARN := 0 @@ -80,34 +48,8 @@ PREFIX := /usr/local # Your C compiler CC := gcc -# This is the main modules directory into which the modules will be installed. -# The magic invocation will return something like this: -# /lib/modules/2.4.29 -KERNELVERSION := $(shell $(CC) -I$(LINUX_HEADERS) -E etc/config.c | grep uts_release | cut -f 2 -d'"') -MODPREF := /lib/modules/$(KERNELVERSION) - -# When building userspace for use with 2.4.x series kernels, we turn off -# sysfs support by default. You can override this (e.g. if you want -# to build binaries that work for both 2.4.x, and 2.6.x and above) -# by uncommenting the line after the next endif. Keep in mind, if and only -# if you do this: you will need to install the libsysfs libraries on your -# kernel 2.4.x systems also. -ifeq (,$(findstring /2.4., $(MODPREF))) - SYSFS_SUPPORT := 1 -else - SYSFS_SUPPORT := -endif -#SYSFS_SUPPORT := 1 - -# Prevent 2.6+ users from using improper targets, as this won't work. -ifeq (,$(findstring /2.4., $(MODPREF))) - ifeq (, $(MAKECMDGOALS)) - $(error For 2.6 kernels and later, use "make user") - endif - ifeq (install, $(MAKECMDGOALS)) - $(error For 2.6 kernels and later, use "make user_install") - endif -endif +# Build with sysfs support +SYSFS_SUPPORT := 1 # This is the directory where sensors.conf will be installed, if no other # configuration file is found @@ -170,19 +112,6 @@ MACHINE := $(shell uname -m) # The subdirectories we need to build things in SRCDIRS := -ifneq ($(MAKECMDGOALS),user) -ifneq ($(MAKECMDGOALS),user_install) -ifneq ($(MAKECMDGOALS),user_uninstall) -ifneq ($(MAKECMDGOALS),package) -ifneq ($(MAKECMDGOALS),userpackage) -ifneq ($(MAKECMDGOALS),manhtml) -SRCDIRS += kernel kernel/chips -endif -endif -endif -endif -endif -endif SRCDIRS += kernel/include SRCDIRS += lib prog/detect prog/dump prog/eeprom prog/pwm \ prog/sensors prog/xeon ${PROG_EXTRA:%=prog/%} etc @@ -204,11 +133,10 @@ SED := sed # Determine the default compiler flags # Set CFLAGS or CPPFLAGS above to add your own flags to all. # ALLCPPFLAGS/ALLCFLAGS are common flags, plus any user-specified overrides from the environment or make command line. -# MODCPPFLAGS/MODCFLAGS is to create in-kernel object files (modules). -# PROGCPPFLAGS/PROGCFLAGS is to create non-kernel object files (which are linked into executables). +# PROGCPPFLAGS/PROGCFLAGS is to create regular object files (which are linked into executables). # ARCPPFLAGS/ARCFLAGS are used to create archive object files (static libraries). # LIBCPPFLAGS/LIBCFLAGS are for shared library objects. -ALL_CPPFLAGS := -I. -Ikernel/include -I$(I2C_HEADERS) +ALL_CPPFLAGS := -I. -Ikernel/include ALL_CFLAGS := -Wall ifeq ($(DEBUG),1) @@ -226,47 +154,6 @@ endif ALL_CPPFLAGS += $(CPPFLAGS) ALL_CFLAGS += $(CFLAGS) -MODCPPFLAGS := -MODCFLAGS := -fno-strict-aliasing - -ifeq ($(MACHINE),alpha) -MODCFLAGS += -ffixed-8 -mno-fp-regs -mcpu=ev56 -endif - -ifeq ($(MACHINE),x86_64) -MODCFLAGS += -fno-common -fomit-frame-pointer -mno-red-zone \ - -mcmodel=kernel -fno-reorder-blocks -finline-limit=2000 -fno-strength-reduce -endif - -ifeq ($(MACHINE),mips) -MODCFLAGS += -mabi=32 -mips3 -Wa,-32 -Wa,-mips3 -Wa,--trap -endif - -ifeq ($(MACHINE),sparc32) -MODCFLAGS += -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7 -endif - -ifeq ($(MACHINE),sparc64) -MODCFLAGS += -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow \ - -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare \ - -Wa,--undeclared-regs -endif - -ifeq ($(SMP),1) -MODCPPFLAGS += -D__SMP__ -endif - -ifeq ($(MODVER),1) -MODCPPFLAGS += -DMODVERSIONS -include $(LINUX_HEADERS)/linux/modversions.h -endif - -# This magic is from the kernel Makefile. -# Extra cflags for kbuild 2.4. The default is to forbid includes by kernel code -# from user space headers. -kbuild_2_4_nostdinc := -nostdinc $(shell LC_ALL=C $(CC) -print-search-dirs | sed -ne 's/install: \(.*\)/-I \1include/gp') - -MODCPPFLAGS += -D__KERNEL__ -DMODULE -DEXPORT_SYMTAB -fomit-frame-pointer $(ALL_CPPFLAGS) -I$(LINUX_HEADERS) $(kbuild_2_4_nostdinc) -MODCFLAGS += $(ALL_CFLAGS) PROGCPPFLAGS := -DETCDIR="\"$(ETCDIR)\"" $(ALL_CPPFLAGS) -Wundef PROGCFLAGS := $(ALL_CFLAGS) ARCPPFLAGS := $(ALL_CPPFLAGS) @@ -317,22 +204,6 @@ user_install:: @echo "*** to fit your needs again." all :: user install :: all user_install -ifeq ($(DESTDIR),) - -if [ -r $(MODPREF)/build/System.map -a -x /sbin/depmod ] ; then \ - /sbin/depmod -a -F $(MODPREF)/build/System.map $(KERNELVERSION) ; \ - fi -else - @echo "*** This is a \`staged' install using \"$(DESTDIR)\" as prefix." - @echo "***" - @echo "*** Once the modules have been moved to their final destination" - @echo "*** you must run the command \"/sbin/depmod -a\"." - @echo "***" - @echo "*** Alternatively, if you build a package (e.g. rpm), include the" - @echo "*** command \"/sbin/depmod -a\" in the post-(un)install procedure." - @echo "***" - @echo "*** The depmod command mentioned above may generate errors. We are" - @echo "*** aware of the problem and are working on a solution." -endif clean:: $(RM) lm_sensors-* lex.backup @@ -340,8 +211,6 @@ clean:: user_uninstall:: uninstall :: user_uninstall - @echo "*** Note:" - @echo "*** * Kernel modules were not uninstalled." # This is tricky, but it works like a charm. It needs lots of utilities # though: cut, find, gzip, ln, tail and tar. @@ -359,23 +228,6 @@ package: version clean $(RM) $$lmpackage.tar $$lmpackage cat doc/developers/checklist -# doesn't work well yet... needs Makefile changes too -userpackage: version clean $(KERNELINCLUDEDIR)/sensors.h - lmversion=`tail -1 version.h|cut -f 2 -d \"`; \ - lmpackage=lm_sensors-user-$$lmversion; \ - ln -s . $$lmpackage; \ - find $$lmpackage/ -type f | grep -v ^$$lmpackage/$$lmpackage$$ | \ - grep -v ^$$lmpackage/$$lmpackage.tar$$ | \ - grep -v ^$$lmpackage/doc/chips | \ - grep -v ^$$lmpackage/kernel/chips | \ - grep -v ^$$lmpackage/$$ | \ - grep -v /CVS | \ - grep -v /\\.# | \ - tar rvf $$lmpackage.tar -T -; \ - gzip -9 $$lmpackage.tar ;\ - $(RM) $$lmpackage.tar $$lmpackage - cat doc/developers/checklist - version: $(RM) version.h echo '#define LM_DATE "'`date +'%Y%m%d'`\" > version.h @@ -384,29 +236,12 @@ version: help: @echo 'Make targets are:' - @echo ' all (default): build modules and userspace programs' - @echo ' install: install modules and userspace programs' - @echo ' user: build userspace programs' - @echo ' user_install: install userspace programs' - @echo ' user_uninstall: remove userspace programs' + @echo ' all (default): build library and userspace programs' + @echo ' install: install library and userspace programs' + @echo ' uninstall: uninstall library and userspace programs' @echo ' clean: cleanup' @echo ' package: create a distribution package' -$(LINUX)/.config: - @echo - @echo "Error - missing file $(LINUX)/.config !! " - @echo " Verify kernel source is in $(LINUX) and then" - @echo " cd to $(LINUX) and run 'make config' !!" - @echo - @echo "Exception: if you're using a stock RedHat kernel..." - @echo " (1) Install the appropriate kernel-source RPM." - @echo " (2) Copy the appropriate config..." - @echo " from $(LINUX)/configs/<...>" - @echo " to $(LINUX)/.config" - @echo " (3) Do *NOT* 'make dep' or 'make config'." - @echo - @exit 1 - # Generate html man pages to be copied to the lm_sensors website. # This uses the man2html from here # http://ftp.math.utah.edu/pub/sgml/ @@ -427,16 +262,6 @@ manhtml: # We need to create dependency files. Tricky. The sed rule puts dir/file.d and # dir/file.c in front of the dependency file rule. -# .o files are used for modules -# depend on the kernel config file! -%.o: %.c $(LINUX)/.config - $(CC) $(MODCPPFLAGS) $(MODCFLAGS) -c $< -o $@ - -%.d: %.c $(LINUX)/.config - $(CC) -M -MG $(MODCPPFLAGS) $(MODCFLAGS) $< | \ - $(SED) -e 's@^\(.*\)\.o:@$*.d $*.o: Makefile '`dirname $*.d`/Module.mk' @' > $@ - - # .ro files are used for programs (as opposed to modules) %.ro: %.c diff --git a/QUICKSTART b/QUICKSTART index bb964bfc..092fc3eb 100644 --- a/QUICKSTART +++ b/QUICKSTART @@ -4,14 +4,11 @@ LM_SENSORS QUICK INSTALLATION INSTRUCTIONS The instructions in this document will generally work if you have a standard system, but not always!! -The first part of document is for 2.6 kernel series, second part is for -older 2.4 kernels. - Quickstart for Kernel 2.6 ------------------------- 0) Just compile and install lm-sensors userspace tools. You can do that with: - 'make user; make user_install' + 'make ; make install' 1) Make sure your kernel has support for all I2C bus drivers and 'i2c device interface'. If you are using a distribution kernel, all is already prepared, you don't need to recompile it. @@ -26,52 +23,3 @@ http://www.lm-sensors.org/wiki/iwizard/1 We are aware that the documentation could be improved, please contact us if you want to help us with that. - -Quickstart for Kernel 2.4 -------------------------- - -NOTE: PLEASE SKIM THE INSTALL DOCUMENT, OR BETTER YET READ IT CAREFULLY! - -Quickstart for i2c option 1 (modules) and lm_sensors option 1 (modules). -This is by far the EASIEST METHOD. -Other methods are described in INSTALL. ------------------------------------------- - - * Verify you are running a 2.4 kernel, 2.4.10 or later. - - * Make sure you have the kernel tree corresponding to your current - kernel in /lib/modules/$(uname -r)/build. - Even if the source is there, it may not correspond to your running - kernel. If so, you will have to recompile your kernel. - - * Verify that your i2c support in the kernel is configured as - modules or is disabled. If it is compiled-in, you obviously - cannot replace it with modules in the next step. - - * Do `lsmod'. If there are any old i2c or sensors modules loaded, - you MUST remove them (as root) with `rmmod'. - - * Download, build, and install the latest i2c package, - (i2c-2.9.0 or later). The i2c subsystem found in the Linux 2.4 - kernel trees, even the latest ones, is outdated and won't work. - Quickstart for i2c: make; (as root) make install - - * Go back to the lm_sensors directory. Do `make'. - The warnings about .d files at the start are harmless. - - * Do (as root) `make install'. - - * Verify that /usr/local/lib is listed in /etc/ld.so.conf; - if it isn't, add it, then run (as root) `ldconfig'. - - * Run (as root) `prog/mkdev/mkdev.sh' to create the device files, - unless you already have them or are running devfs or udev. - - * Run (as root) `prog/detect/sensors-detect' to detect your hardware, - put the lines it suggests into /etc/modules.conf, and run all - the commands it suggests (`modprobe X', `sensors -s'). - - * Run `sensors' to see your output. - - * That's it! If you have problems, read our excellent FAQ - (doc/FAQ or doc/lm_sensors-FAQ.html). diff --git a/README.directories b/README.directories index 37a50074..f5c29871 100644 --- a/README.directories +++ b/README.directories @@ -1,11 +1,11 @@ The directories within this package: * doc - Documentation about the modules within this package, and all other things. + Documentation. * etc A sample configuration file for the 'sensors' program. * kernel - The kernel modules: sensor chip drivers. + A few kernel-related header files. * lib The user-space sensors support library code. * prog diff --git a/doc/chips/adm1021 b/doc/chips/adm1021 deleted file mode 100644 index c3bb602b..00000000 --- a/doc/chips/adm1021 +++ /dev/null @@ -1,415 +0,0 @@ -Kernel driver `adm1021.o' -========================= - -Status: Complete; tested for most devices except Xeon. - -Supported chips: - * Analog Devices ADM1021 - Prefix: 'adm1021' - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the Analog Devices website - * Analog Devices ADM1021A/ADM1023 - Prefix: 'adm1023' - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the Analog Devices website - * Genesys Logic GL523SM - Prefix: 'gl523sm' - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: - * Intel Xeon Processor - Prefix - any other - may require 'force_adm1021' parameter - - see MODPARMS and xeontemp files for more information - Addresses scanned: none - Datasheet: Publicly available at Intel website - Status: Alpha, untested. - * Maxim MAX1617 - Prefix: 'max1617' - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the Maxim website - * Maxim MAX1617A - Prefix: 'max1617a' - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the Maxim website - * National Semiconductor LM84 - Prefix: 'lm84' - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the National Semiconductor website - * Philips NE1617 - Prefix: 'max1617' (probably detected as a max1617) - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the Philips website - * Philips NE1617A - Prefix: 'max1617' (probably detected as a max1617) - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the Philips website - * TI THMC10 - Prefix: 'thmc10' - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the TI website - * Onsemi MC1066 - Prefix: 'mc1066' - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the Onsemi website - - -Author: Frodo Looijaard and Philip Edelbrock - - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_adm1021: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adm1021' chip -* force_adm1023: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adm1023' chip -* force_max1617: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `max1617' chip -* force_max1617a: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `max1617a' chip -* force_thmc10: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `thmc10' chip -* force_lm84: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm84' chip -* force_gl523sm: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `gl523sm' chip -* force_mc1066: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `mc1066' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* read_only: int - Don't set any values, read only mode - - -Description ------------ - -The chips supported by this driver are very similar. The Maxim MAX1617 -is the oldest; it has the problem that it is not very well detectable. -The MAX1617A solves that. The ADM1021 is a straight clone of the MAX1617A. -Ditto for the THMC10. -From here on, we will refer to all these chips as ADM1021-clones. - -ADM1021-clones implement two temperature sensors. One of them is internal, -and measures the temperature of the chip itself; the other is external -and is realised in the form of a transistor-like device. A special alarm -indicates whether the remote sensor is connected. - -Each sensor has its own low and high limits. When they are crossed, the -corresponding alarm is set and remains on as long as the temperature stays -out of range. Temperatures are measured in degrees Celsius. Measurements -are possible between -65 and +127 degrees, with a resolution of one degree. - -The ADM1021 reports a die code, which is a sort of revision code. This -can help us pinpoint problems; it is not very useful otherwise. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! - -This driver only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. It is possible to make -ADM1021-clones do faster measurements, but there is really no good reason -for that. - - -Xeon support ------------- -Some Xeon processors have real max1617, adm1021, or compatible chips -with in them, with two temperature sensors. - -Other Xeons have chips with only one sensor. - -If you have a Xeon, and the adm1021 module loads, and both -temperatures appear valid, then things are good. - -If the adm1021 module doesn't load, you should try two things: - 1) modprobe adm1021 force_adm1021=BUS,ADDRESS - ADDRESS can only be 0x18, 0x1a, 0x29, 0x2b, 0x4c, or 0x4e. - See if you have one or two valid temperatures - - 2) modprobe xeontemp - See if you have one valid temperature. - -If you have dual Xeons you may have appear to have two separate -adm1021-compatible chips, or two single-temperature sensors, -at distinct addresses. - -Pick the best module for your processor based on the results. -See the xeontemp documentation for further information. - - -Chip Features -------------- - -Chip 'adm1021' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 0 -temp_low temp temp RW 0 -temp_over temp temp RW 0 -remote_temp - - R- 0 -remote_temp_low remote_temp remote_temp RW 0 -remote_temp_over remote_temp remote_temp RW 0 -alarms - - R- 0 -die_code - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_ADM1021_TEMP temp1:3 -temp_low SENSORS_ADM1021_TEMP_HYST temp1:2 -temp_over SENSORS_ADM1021_TEMP_OVER temp1:1 -remote_temp SENSORS_ADM1021_REMOTE_TEMP temp2:3 -remote_temp_low SENSORS_ADM1021_REMOTE_TEMP_HYST temp2:2 -remote_temp_over SENSORS_ADM1021_REMOTE_TEMP_OVER temp2:1 -alarms SENSORS_ADM1021_ALARMS alarms:1 -die_code SENSORS_ADM1021_DIE_CODE die_code:1 - - -Chip 'adm1023' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 0 -temp_low temp temp RW 0 -temp_over temp temp RW 0 -remote_temp - - R- 3 -remote_temp_low remote_temp remote_temp RW 3 -remote_temp_over remote_temp remote_temp RW 3 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_ADM1021_TEMP temp1:3 -temp_low SENSORS_ADM1021_TEMP_HYST temp1:2 -temp_over SENSORS_ADM1021_TEMP_OVER temp1:1 -remote_temp SENSORS_ADM1021_REMOTE_TEMP temp2:4 -remote_temp_low SENSORS_ADM1021_REMOTE_TEMP_HYST temp2:2 -remote_temp_over SENSORS_ADM1021_REMOTE_TEMP_OVER temp2:1 -alarms SENSORS_ADM1021_ALARMS alarms:1 - - -Chip 'max1617' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 0 -temp_low temp temp RW 0 -temp_over temp temp RW 0 -remote_temp - - R- 0 -remote_temp_low remote_temp remote_temp RW 0 -remote_temp_over remote_temp remote_temp RW 0 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_MAX1617_TEMP temp1:3 -temp_low SENSORS_MAX1617_TEMP_HYST temp1:2 -temp_over SENSORS_MAX1617_TEMP_OVER temp1:1 -remote_temp SENSORS_MAX1617_REMOTE_TEMP temp2:3 -remote_temp_low SENSORS_MAX1617_REMOTE_TEMP_HYST temp2:2 -remote_temp_over SENSORS_MAX1617_REMOTE_TEMP_OVER temp2:1 -alarms SENSORS_MAX1617_ALARMS alarms:1 - - -Chip 'max1617a' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 0 -temp_low temp temp RW 0 -temp_over temp temp RW 0 -remote_temp - - R- 0 -remote_temp_low remote_temp remote_temp RW 0 -remote_temp_over remote_temp remote_temp RW 0 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_MAX1617A_TEMP temp1:3 -temp_low SENSORS_MAX1617A_TEMP_HYST temp1:2 -temp_over SENSORS_MAX1617A_TEMP_OVER temp1:1 -remote_temp SENSORS_MAX1617A_REMOTE_TEMP temp2:3 -remote_temp_low SENSORS_MAX1617A_REMOTE_TEMP_HYST temp2:2 -remote_temp_over SENSORS_MAX1617A_REMOTE_TEMP_OVER temp2:1 -alarms SENSORS_MAX1617A_ALARMS alarms:1 - - -Chip 'thmc10' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 0 -temp_low temp temp RW 0 -temp_over temp temp RW 0 -remote_temp - - R- 0 -remote_temp_low remote_temp remote_temp RW 0 -remote_temp_over remote_temp remote_temp RW 0 -alarms - - R- 0 -die_code - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_ADM1021_TEMP temp1:3 -temp_low SENSORS_ADM1021_TEMP_HYST temp1:2 -temp_over SENSORS_ADM1021_TEMP_OVER temp1:1 -remote_temp SENSORS_ADM1021_REMOTE_TEMP temp2:3 -remote_temp_low SENSORS_ADM1021_REMOTE_TEMP_HYST temp2:2 -remote_temp_over SENSORS_ADM1021_REMOTE_TEMP_OVER temp2:1 -alarms SENSORS_ADM1021_ALARMS alarms:1 -die_code SENSORS_ADM1021_DIE_CODE die_code:1 - - -Chip 'lm84' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 0 -temp_low temp temp RW 0 -temp_over temp temp RW 0 -remote_temp - - R- 0 -remote_temp_low remote_temp remote_temp RW 0 -remote_temp_over remote_temp remote_temp RW 0 -alarms - - R- 0 -die_code - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_ADM1021_TEMP temp1:3 -temp_low SENSORS_ADM1021_TEMP_HYST temp1:2 -temp_over SENSORS_ADM1021_TEMP_OVER temp1:1 -remote_temp SENSORS_ADM1021_REMOTE_TEMP temp2:3 -remote_temp_low SENSORS_ADM1021_REMOTE_TEMP_HYST temp2:2 -remote_temp_over SENSORS_ADM1021_REMOTE_TEMP_OVER temp2:1 -alarms SENSORS_ADM1021_ALARMS alarms:1 -die_code SENSORS_ADM1021_DIE_CODE die_code:1 - - -Chip 'gl523' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 0 -temp_low temp temp RW 0 -temp_over temp temp RW 0 -remote_temp - - R- 0 -remote_temp_low remote_temp remote_temp RW 0 -remote_temp_over remote_temp remote_temp RW 0 -alarms - - R- 0 -die_code - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_ADM1021_TEMP temp1:3 -temp_low SENSORS_ADM1021_TEMP_HYST temp1:2 -temp_over SENSORS_ADM1021_TEMP_OVER temp1:1 -remote_temp SENSORS_ADM1021_REMOTE_TEMP temp2:3 -remote_temp_low SENSORS_ADM1021_REMOTE_TEMP_HYST temp2:2 -remote_temp_over SENSORS_ADM1021_REMOTE_TEMP_OVER temp2:1 -alarms SENSORS_ADM1021_ALARMS alarms:1 -die_code SENSORS_ADM1021_DIE_CODE die_code:1 - - -Chip 'mc1066' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 0 -temp_low temp temp RW 0 -temp_over temp temp RW 0 -remote_temp - - R- 0 -remote_temp_low remote_temp remote_temp RW 0 -remote_temp_over remote_temp remote_temp RW 0 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_MAX1617_TEMP temp1:3 -temp_low SENSORS_MAX1617_TEMP_HYST temp1:2 -temp_over SENSORS_MAX1617_TEMP_OVER temp1:1 -remote_temp SENSORS_MAX1617_REMOTE_TEMP temp2:3 -remote_temp_low SENSORS_MAX1617_REMOTE_TEMP_HYST temp2:2 -remote_temp_over SENSORS_MAX1617_REMOTE_TEMP_OVER temp2:1 -alarms SENSORS_MAX1617_ALARMS alarms:1 - - - - - -Old Documentation (may be outdated) ------------------------------------ - -This file documents the adm1021 directories for the Analog Devices ADM1021 -and MAX1617 temperature sensor chip. Note that this last chip should be -fully compatible; it is not yet well-tested, though. - -There will be one directory created for each detected ADM1021 chip. As -ADM1021 chips can only be on a SMBus, they will be called adm1021-i2c-?-??, with -the first question mark being the number of the i2c bus (see /proc/bus/i2c -for a list of them, if i2c-proc is loaded), and the SMBus (I2C) address -of the chip at the end. An ADM1021 is uniquely characterised with these -two numbers. Likewise, for each MAX1617 chip, a directory max1617-i2c-?-?? -will be created. /proc/sys/dev/sensors/chips contains the SYSCTL values for -all chip directories. - -Within each ADM1021 or MAX1617 directory, you can find the following files: -* die_code (ADM1021_SYSCTL_DIE_CODE) - Silicon die (mask) revision code. This driver was written using a sample - device of die code 3. Normally this kind of information isn't reported - in its own proc file, but for a device this simple I didn't think it - would hurt. -* status (ADM1021_SYSCTL_STATUS) - This is an intergral number composed of 8-bits, which indicate the - different alarms and conversion status's of the chip. Here is what - each bit indicates: - 7 BUSY 1 When ADC Converting. - 6 LHIGH# 1 When Local High Temp Limit Tripped. - 5 LLOW# 1 When Local Low Temp Limit Tripped. - 4 RHIGH# 1 When Remote High Temp Limit Tripped. - 3 RLOW# 1 When Remote Low Temp Limit Tripped. - 2 OPEN# 1 When Remote Sensor Open-Circuit. (i.e., no connected remote - sensor) - 1-0 Reserved. - Note: # - These flags stay high until the status register is read or they - are reset by POR. -* temp1 (ADM1021_SYSCTL_TEMP) - A list of three numbers. The first number is the Overtemperature Shutdown - value, the second number is Low limit value, and the third number is the - current temperature. The first two values can be modified. Each value can - be set and read to full-degree accuracy. All values are in degrees Celsius. - An alarm is issued (usually to a connected ADM9240) when the temperature - gets higher then the Overtemperature Shutdown value; it stays on until - the temperature falls back below the Overtemperature Shutdown value. - NOTE: This is different than the way most remote temperature sensors work - (e.g. the LM75), they usually use the lower limit to clear the alarm set - from initially going above the Overtemperature limit. Instead, the - ADM1021 acts much the way that voltage limits work on, say, the LM78 or - ADM9240. A disadvantage to this is that the alarm doesn't have a - hysteresis (like a shmidt-trigger or thermostat) type of function for - doing things like controlling over-heat fans and such. Instead, the - lower limit can be used to signal an alarm if (goodness forbid!) the - computer gets too cold. - If accessed through sysctl, this is a list of longs, each being the - temperature times 10. -* temp2 (ADM1021_SYSCTL_REMOTE_TEMP) - Works exactly the same way as 'temp1', but uses an external temperature - probe for the sensing. The temperature probe is of a silicon diode type - and not of a thermal-resistive type. A probe can easily be made from a - common transister (see the ADM1021 for qualification specs) by shorting - the base to the collector. From the docs: "Transistors such as 2N3904, - 2N3906 or equivalents in SOT-23 package are suitable to use." - -The data for each chip is updated each 1.5 seconds, but only if it is -actually read. And, any alarms triggered between reads which always be -present in the next read just after the alarm was triggered (regardless if -the alarm situation has been resolved or not). - -This driver was written and is maintained by Philip Edelbrock -. Please send corrections/comments to him. For -further technical information on this chip, please get the Acrobat PDF -documentation available from www.analog.com. We'd also like to thank -Analog Devices for helping us with correspondance and free samples to make -this driver (and other Analog Devices drivers) possible. diff --git a/doc/chips/adm1024 b/doc/chips/adm1024 deleted file mode 100644 index 4965fa61..00000000 --- a/doc/chips/adm1024 +++ /dev/null @@ -1,12 +0,0 @@ -Kernel driver `adm1024.o' -========================= - -Status: Complete; Alpha. - -Supported chips: - * Analog Devices ADM1024 - Prefix: 'adm1024' - Addresses scanned: I2C 0x2c - 0x2e - Datasheet: Publicly available at the Analog Devices website - -Author: Ken Bowley diff --git a/doc/chips/adm1025 b/doc/chips/adm1025 deleted file mode 100644 index 0a2ab693..00000000 --- a/doc/chips/adm1025 +++ /dev/null @@ -1,135 +0,0 @@ -Kernel driver `adm1025.o' -========================= - -Status: Complete, known to work but not heavily tested - -Supported chips: - * Analog Devices ADM1025 - Prefix: 'adm1025' - Addresses scanned: I2C 0x2c - 0x2e - Datasheet: Publicly available at the Analog Devices website - * Philips NE1619 - Prefix: 'ne1619' - Addresses scanned: I2C 0x2c - 0x2d - Datasheet: Publicly available at the Philips website - -The NE1619 presents some differences with the original ADM1025: - * Only two possible addresses (0x2c - 0x2d). - * No temperature offset register, but we don't use it anyway. - * No INT mode for pin 16. We don't play with it anyway. - -Author: Chen-Yuan Wu and Jean Delvare - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_adm1025: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adm1025' chip -* force_ne1619: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `ne1619' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -(This is from Analog Devices.) The ADM1025 is a complete system hardware -monitor for microprocessor-based systems, providing measurement and limit -comparison of various system parameters. Five voltage measurement inputs -are provided, for monitoring +2.5V, +3.3V, +5V and +12V power supplies and -the processor core voltage. The ADM1025 can monitor a sixth power-supply -voltage by measuring its own VCC. One input (two pins) is dedicated to a -remote temperature-sensing diode and an on-chip temperature sensor allows -ambient temperature to be monitored. - -One specificity of this chip is that the pin 11 can be hardwired in two -different manners. It can act as the +12V power-supply voltage analog -input, or as the a fifth digital entry for the VID reading (bit 4). It's -kind of strange since both are useful, and the reason for designing the -chip that way is obscure at least to me. The bit 5 of the configuration -register can be used to define how the chip is hardwired. Please note -that it is not a choice you have to make as the user. The choice was -already made by your motherboard's maker. If the configuration bit isn't -set properly, you'll have a wrong +12V reading or a wrong VID reading. -The way the driver handles that is to preserve this bit through the -initialization process, assuming that the BIOS set it up properly -beforehand. If it turns out not to be true in some cases, we'll provide -a module parameter to force modes. - - -Chip Features -------------- - -Chips 'adm1025' and 'ne1619' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -in0 - - R- 2 -in1 - - R- 2 -in2 - - R- 2 -in3 - - R- 2 -in4 - - R- 2 -in5 - - R- 2 -in0_min in0 in0 RW 2 -in1_min in1 in1 RW 2 -in2_min in2 in2 RW 2 -in3_min in3 in3 RW 2 -in4_min in4 in4 RW 2 -in5_min in5 in5 RW 2 -in0_max in0 in0 RW 2 -in1_max in1 in1 RW 2 -in2_max in2 in2 RW 2 -in3_max in3 in3 RW 2 -in4_max in4 in4 RW 2 -in5_max in5 in5 RW 2 -temp1 - - R- 1 -temp1_low temp1 temp1 RW 1 -temp1_high temp1 temp1 RW 1 -temp2 - - R- 1 -temp2_low temp2 temp2 RW 1 -temp2_high temp2 temp2 RW 1 -vid - - R- 3 -vrm - - RW 1 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -in0 SENSORS_ADM1025_IN0 in0:3 -in1 SENSORS_ADM1025_IN1 in1:3 -in2 SENSORS_ADM1025_IN2 in2:3 -in3 SENSORS_ADM1025_IN3 in3:3 -in4 SENSORS_ADM1025_IN4 in4:3 -in5 SENSORS_ADM1025_IN5 in5:3 -in0_min SENSORS_ADM1025_IN0_MIN in0:1 -in1_min SENSORS_ADM1025_IN1_MIN in1:1 -in2_min SENSORS_ADM1025_IN2_MIN in2:1 -in3_min SENSORS_ADM1025_IN3_MIN in3:1 -in4_min SENSORS_ADM1025_IN4_MIN in4:1 -in5_min SENSORS_ADM1025_IN5_MIN in5:1 -in0_max SENSORS_ADM1025_IN0_MAX in0:2 -in1_max SENSORS_ADM1025_IN1_MAX in1:2 -in2_max SENSORS_ADM1025_IN2_MAX in2:2 -in3_max SENSORS_ADM1025_IN3_MAX in3:2 -in4_max SENSORS_ADM1025_IN4_MAX in4:2 -in5_max SENSORS_ADM1025_IN5_MAX in5:2 -temp1 SENSORS_ADM1025_TEMP1 temp1:3 -temp1_low SENSORS_ADM1025_TEMP1_LOW temp1:2 -temp1_high SENSORS_ADM1025_TEMP1_HIGH temp1:1 -temp2 SENSORS_ADM1025_TEMP2 temp2:3 -temp2_low SENSORS_ADM1025_TEMP2_LOW temp2:2 -temp2_high SENSORS_ADM1025_TEMP2_HIGH temp2:1 -vid SENSORS_ADM1025_VID vid:1 -vrm SENSORS_ADM1025_VRM vrm:1 -alarms SENSORS_ADM1025_ALARMS alarms:1 diff --git a/doc/chips/adm1026 b/doc/chips/adm1026 deleted file mode 100644 index 6330927a..00000000 --- a/doc/chips/adm1026 +++ /dev/null @@ -1,217 +0,0 @@ -Kernel driver `adm1026.o' -====================== - -Status: In development - -Supported chips: - * Analog Devices ADM1026 - Prefix: 'adm1026' - Addresses scanned: I2C 0x2c, 0x2d, 0x2e - -Author: Philip Pokorny - for Penguin Computing - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_adm1026: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - an `adm1026' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - -The following only apply to the first ADM1026 detected. These are a -workaround for if your BIOS hasn't setup your chip. - -* gpio_input: int array (min = 1, max = 17) - List of GPIO pins (0-16) to program as inputs -* gpio_output: int array (min = 1, max = 17) - List of GPIO pins (0-16) to program as outputs -* gpio_inverted: int array (min = 1, max = 17) - List of GPIO pins (0-16) to program as inverted -* gpio_normal: int array (min = 1, max = 17) - List of GPIO pins (0-16) to program as normal/non-inverted -* gpio_fan: int array (min = 1, max = 8) - List of GPIO pins (0-7) to program as fan tachs - - -Description ------------ - -This driver implements support for the Analog Devices ADM1026. Analog -Devices calls it a "complete thermal system management controller." - -The ADM1026 implements three (3) temperature sensors, 17 voltage -sensors, 16 general purpose digital I/O lines, eight (8) fan speed -sensors (8-bit), an analog output and a PWM output along with limit, -alarm and mask bits for all of the above. There is even 8k bytes of -EEPROM memory on chip. - -Temperatures are measured in degrees Celsius. There are two external -sensor inputs and one internal sensor. Each sensor has a high and low -limit. If the limit is exceeded, an interrupt (#SMBALERT) can be -generated. The interrupts can be masked. In addition, there are -over-temp limits for each sensor. If this limit is exceeded, the -#THERM output will be asserted. The current temperature and limits -have a resolution of 1 degree. - -Fan rotation speeds are reported in RPM (rotations per minute) but -measured in counts of a 22.5kHz internal clock. Each fan has a high -limit which corresponds to a minimum fan speed. If the limit is -exceeded, an interrupt can be generated. Each fan can be programmed -to divide the reference clock by 1, 2, 4 or 8. Not all RPM values can -accurately be represented, so some rounding is done. With a divider of -8, the slowest measureable speed of a one pulse per rev fan is 1323 -RPM. Two pulse per rev fans can be measured as slow as 661 RPM. - -Voltage sensors (in0 to in16) report their values in volts. An alarm -is triggered if the voltage has crossed a programmable minimum or -maximum limit. Note that minimum in this case always means 'closest -to zero'; this is important for negative voltage measurements. -Several inputs have integrated attenuators so they can measure higher -voltages directly. 3.3V, 5V, 12V, -12V and battery voltage all have -dedicated inputs. There are several inputs scaled to 0-3V full-scale -range for SCSI terminator power. The remaining inputs are not scaled -and have a 0-2.5V full-scale range. A 2.5V or 1.82V reference voltage -is provided for negative voltage measurements. - -If an alarm triggers, it will remain triggered until the hardware -register is read at least once. This means that the cause for the -alarm may already have disappeared! Note that in the current -implementation, all hardware registers are read whenever any data is -read (unless it is less than 2.0 seconds since the last update). This -means that you can easily miss once-only alarms. - -The ADM1026 measures continuously. Analog inputs are measured about 4 -times a second. Fan speed measurement time depends on fan speed and -divisor. It can take as long as 1.5 seconds to measure all fan -speeds. - -The ADM1026 has the ability to automaticaly control fan speed based on -the temperature sensor inputs. Both the PWM output and the DAC output -can be used to control fan speed. Usually only one of these two -outputs will be used. Write the minimum PWM or DAC value to the -appropriate control register. Then set the low temperature limit in -the tmin values for each temperature sensor. The range of control is -fixed at 20 degC, and the largest difference between current and tmin -of the temperature sensors sets the control output. See the datasheet -for several example circuits for controlling fan speed with the PWM -and DAC outputs. The fan speed sensors do not have PWM compensation, -so it is probably best to control the fan voltage from the power -lead rather than on the ground lead. - -The datasheet shows an example application with VID signals attached -to GPIO lines. Unfortunately, the chip may not be connected to the -VID lines in this way. The driver assumes that the chips *is* -connected this way to get a vid voltage. If the VID value is wrong or -not wired as shown in the example, then you will need to write the -correct VID value to the driver either based on the GPIO values or -setting it directly. The value written to VID should be the *raw* VID -value (0 to 0x3f) or -1 (to restore the default value). When read, -the vid interface returns the scaled voltage according to the VRM spec -selected. - -Example sensors.conf --------------------- - -Here is an example sensors.conf configuration section for the ADM1026. - ---------- cut here --------- -chip "adm1026-*" - -# Voltage inputs - label in0 "V2.25_0" # Scaled for "SCSI terminator"? - label in1 "V2.25_1" # supply voltage? - label in2 "V2.25_2" - label in3 "V2.25_3" - label in4 "V2.25_4" - label in5 "V2.25_5" - - label in6 "V1.875_0" # Unscaled inputs - label in7 "V1.875_1" - -# If temp3 is enabled, in8 and in9 are disabled. -# label in8 "V1.875_2" -# label in9 "V1.875_3" - ignore in8 - ignore in9 - -# Dedicated voltage inputs - label in10 "Vbat" - label in11 "V3.3STBY" - label in12 "V3.3MAIN" - label in13 "V5" - label in14 "Vccp" - label in15 "V12" - label in16 "V-12" - -# Temperature inputs - label temp1 "Board" - label temp2 "CPU0" - label temp3 "CPU1" - -# Fan inputs - label fan0 "CPU_Fan" - label fan1 "Fan1" - label fan2 "Fan2" - label fan3 "Fan3" - label fan4 "Fan4" - label fan5 "Fan5" - label fan6 "Fan6" - label fan7 "Fan7" - -# PWM Outputs - label pwm "PWM" - -# Voltage scaling is done on-chip. No 'compute' directive -# should be necessary. If in0-in9 have external scaling, -# set it here. - -# compute in0 @ * 2.5, @ / 2.5 - -# Adjust fans speeds for actual pulses per rev -# compute fan0 @ / 2, @ * 2 # 2 pulse per rev -# compute fan1 @ / 3, @ * 3 # 3 pulse per rev -# compute fan2 @ / 4, @ * 4 # 4 pulse per rev -# compute fan3 @ / 8, @ * 8 # 8 pulse per rev - -# Set VRM version - set vrm 9.1 -# set vid 1.580 - -# Set voltage limits - set in10_min 3.0 * 0.95 - set in10_max 3.0 * 1.05 - set in11_min 3.3 * 0.95 - set in11_max 3.3 * 1.05 - set in12_min 3.3 * 0.95 - set in12_max 3.3 * 1.05 - set in13_min 5.0 * 0.95 - set in13_max 5.0 * 1.05 -# Uncomment if VID is wired or set above -# set in14_min vid * 0.95 -# set in14_max vid * 1.05 - set in15_min 12 * 0.95 - set in15_max 12 * 1.05 - set in16_min -12 * 0.95 - set in16_max -12 * 1.05 - -# Set Fan limits - set fan0_min 7000 - set fan1_min 7000 - set fan2_min 7000 - set fan3_min 7000 - set fan4_min 3000 - set fan5_min 3000 - set fan6_min 3000 - set fan7_min 3000 - diff --git a/doc/chips/adm1031 b/doc/chips/adm1031 deleted file mode 100644 index db59c94b..00000000 --- a/doc/chips/adm1031 +++ /dev/null @@ -1,109 +0,0 @@ -Kernel driver `adm1031.o' -========================= - -Status: Driver supports basic temp and fan readings, min/max/crit settings - alarms. This driver does not support auto fan control. - -Supported chips: - * Analog Devices ADM1030 - Prefix: 'adm1030' - Addresses scanned: I2C 0x2c to 0x2e - Datasheet: Publicly available at the Analog Devices website - http://products.analog.com/products/info.asp?product=ADM1030 - - * Analog Devices ADM1031 - Prefix: 'adm1031' - Addresses scanned: I2C 0x2c to 0x2e - Datasheet: Publicly available at the Analog Devices website - http://products.analog.com/products/info.asp?product=ADM1031 - - -Author: Alexandre d'Alton - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_adm1030: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adm1030' chip -* force_adm1031: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adm1031' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -ADM1030 and ADM1031 are digital temperature sensors and fan controllers. -They sense their own temperature as well as the temperature of up to one -(ADM1030) or two (ADM1031) external diodes. - -All temperature values are given in degrees Celsius. Resolution -is 0.5 degree for the local temperature, 0.125 degree for the remote -temperatures. - -Each temperature channel has its own high and low limits, plus a critical -limit. - -The ADM1030 monitors a single fan speed, while the ADM1031 monitors up to -two. Each fan channel has its own low speed limit. - - -Chip Features -------------- - -Chip 'adm1030' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp1 - - R- 3 -temp1_high temp1 temp1 RW 3 -temp1_low temp1 temp1 RW 3 -temp1_crit temp1 temp1 RW 3 -temp2 - - R- 3 -temp2_high temp2 temp2 RW 3 -temp2_low temp2 temp2 RW 3 -temp2_crit temp2 temp2 RW 3 - -fan1_input - - R- 0 -fan1_min fan1 fan1 RW 0 -fan1_div fan1 - RW 0 - -alarms - - R- 0 - -Chip 'adm1031' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp1 - - R- 3 -temp1_high temp1 temp1 RW 3 -temp1_low temp1 temp1 RW 3 -temp1_crit temp1 temp1 RW 3 -temp2 - - R- 3 -temp2_high temp2 temp2 RW 3 -temp2_low temp2 temp2 RW 3 -temp2_crit temp2 temp2 RW 3 -temp3 - - R- 3 -temp3_high temp3 temp3 RW 3 -temp3_low temp3 temp3 RW 3 -temp3_crit temp3 temp3 RW 3 - -fan1_input - - R- 0 -fan1_min fan1 fan1 RW 0 -fan1_div fan1 - RW 0 -fan2_input - - R- 0 -fan2_min fan2 fan2 RW 0 -fan2_div fan2 - RW 0 - -alarms - - R- 0 diff --git a/doc/chips/adm9240 b/doc/chips/adm9240 deleted file mode 100644 index bdad871d..00000000 --- a/doc/chips/adm9240 +++ /dev/null @@ -1,424 +0,0 @@ -Kernel driver `adm9240.o' -========================= - -Status: Complete and tested - -Supported chips: - * Analog Devices ADM9240 - Prefix: 'adm9240' - Addresses scanned: I2C 0x2c - 0x2f - Datasheet: Publicly available at the Analog Devices website - * Dallas Semiconductor DS1780 - Prefix: 'ds1780' - Addresses scanned: I2C 0x2c - 0x2f - Datasheet: Publicly available at the Dallas Semiconductor website - * National Semiconductor LM81 - Prefix: 'lm81' - Addresses scanned: I2C 0x2c - 0x2f - Datasheet: Publicly available at the National Semiconductor website - - -Author: Frodo Looijaard and Philip Edelbrock - - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_adm9240: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adm9240' chip -* force_ds1780: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `ds1780' chip -* force_lm81: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm81' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This driver implements support for the Analog Devices ADM9240, -Dallas Semiconductor DS1780, and National Semiconductor LM81 chips. -These chips appear to be completely -identical, except for the manufacturer IDs encoded in two registers, and -the speed with which they update their sensor readings. - -The chips implement six voltage sensors, a temperature sensor, -two fan rotation speed sensors, VID lines and some miscellaneous stuff. - -Temperatures are measured in degrees Celsius. An alarm is triggered whenever -the temperature is above the hot limit, and will continue to be generated -until the temperature has dropped beneath the hysteresis limit. Measurements -are guaranteed between -40 and +125 degrees. The current temperature -has a resolution of 0.5 degrees, the limits of 1 degree. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -Voltage sensors (also known as IN sensors) report their values in volts. -An alarm is triggered if the voltage has crossed a programmable minimum -or maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. -IMPORTANT: The current voltage measurement system is very probably broken. -Please report back to us if you have a ADM9240 or DS1780! - -The VID lines encode the core voltage value: the voltage level your processor -should work with. This is hardcoded by the mainboard and/or processor itself. -It is a value in volts. When it is unconnected, you will often find the -value 3.50 V here. - -The analog output can be programmed separatedly. It can take values -between 0 and 255. What it actually does is mainboard-dependent; it -might influence the fan speed. Please report to us whether this is -the case with your ADM9240. - -In addition to the alarms described above, the CHAS alarm triggers -if your computer case is open. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.5 seconds since the last update). This means that you can easily -miss once-only alarms. - -Thes ADM9240 only updates its values every 0.5 seconds; the DS1780 one -every 2 seconds; and the LM81 every 0.4 seconds. -Reading them more often will do no harm, but will return -'old' values. (NB: theoretically, this could be done much faster for the -ADM9240, but there is no real reason to do so, and this way the SMBus use -is kept within reasonable limits) - - -Chip Features -------------- - -Chip `adm9240' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - 2.5V NONE NONE R 2 - Vccp1 NONE NONE R 2 - 3.3V NONE NONE R 2 - 5V NONE NONE R 2 - 12V NONE NONE R 2 - Vccp2 NONE NONE R 2 - 2.5V_min 2.5V 2.5V RW 2 - Vccp1_min Vccp1 Vccp1 RW 2 - 3.3V_min 3.3V 3.3V RW 2 - 5V_min 5V 5V RW 2 - 12V_min 12V 12V RW 2 - Vccp2_min Vccp2 Vccp2 RW 2 - 2.5V_max 2.5V 2.5V RW 2 - Vccp1_max Vccp1 Vccp1 RW 2 - 3.3V_max 3.3V 3.3V RW 2 - 5V_max 5V 5V RW 2 - 12V_max 12V 12V RW 2 - Vccp2_max Vccp2 Vccp2 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - alarms NONE NONE R 0 - analog_out NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - 2.5V SENSORS_ADM9240_IN0 2.5V:3 - Vccp1 SENSORS_ADM9240_IN1 Vccp1:3 - 3.3V SENSORS_ADM9240_IN2 3.3V:3 - 5V SENSORS_ADM9240_IN3 5V:3 - 12V SENSORS_ADM9240_IN4 12V:3 - Vccp2 SENSORS_ADM9240_IN5 Vccp2:3 - 2.5V_min SENSORS_ADM9240_IN0_MIN 2.5V:1 - Vccp1_min SENSORS_ADM9240_IN1_MIN Vccp1:1 - 3.3V_min SENSORS_ADM9240_IN2_MIN 3.3V:1 - 5V_min SENSORS_ADM9240_IN3_MIN 5V:1 - 12V_min SENSORS_ADM9240_IN4_MIN 12V:1 - Vccp2_min SENSORS_ADM9240_IN5_MIN Vccp2:1 - 2.5V_max SENSORS_ADM9240_IN0_MAX 2.5V:2 - Vccp1_max SENSORS_ADM9240_IN1_MAX Vccp1:2 - 3.3V_max SENSORS_ADM9240_IN2_MAX 3.3V:2 - 5V_max SENSORS_ADM9240_IN3_MAX 5V:2 - 12V_max SENSORS_ADM9240_IN4_MAX 12V:2 - Vccp2_max SENSORS_ADM9240_IN5_MAX Vccp2:2 - fan1 SENSORS_ADM9240_FAN1 fan1:2 - fan2 SENSORS_ADM9240_FAN2 fan2:2 - fan1_min SENSORS_ADM9240_FAN1_MIN fan1:1 - fan2_min SENSORS_ADM9240_FAN2_MIN fan2:1 - temp SENSORS_ADM9240_TEMP temp:3 - temp_hyst SENSORS_ADM9240_TEMP_HYST temp:2 - temp_over SENSORS_ADM9240_TEMP_OVER temp:1 - vid SENSORS_ADM9240_VID vid:1 - fan1_div SENSORS_ADM9240_FAN1_DIV fan_div:1 - fan2_div SENSORS_ADM9240_FAN2_DIV fan_div:2 - alarms SENSORS_ADM9240_ALARMS alarms:1 - analog_out SENSORS_ADM9240_ANALOG_OUT analog_out:1 - - -Chip `ds1780' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - 2.5V NONE NONE R 2 - Vccp1 NONE NONE R 2 - 3.3V NONE NONE R 2 - 5V NONE NONE R 2 - 12V NONE NONE R 2 - Vccp2 NONE NONE R 2 - 2.5V_min 2.5V 2.5V RW 2 - Vccp1_min Vccp1 Vccp1 RW 2 - 3.3V_min 3.3V 3.3V RW 2 - 5V_min 5V 5V RW 2 - 12V_min 12V 12V RW 2 - Vccp2_min Vccp2 Vccp2 RW 2 - 2.5V_max 2.5V 2.5V RW 2 - Vccp1_max Vccp1 Vccp1 RW 2 - 3.3V_max 3.3V 3.3V RW 2 - 5V_max 5V 5V RW 2 - 12V_max 12V 12V RW 2 - Vccp2_max Vccp2 Vccp2 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - alarms NONE NONE R 0 - analog_out NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - 2.5V SENSORS_DS1780_IN0 2.5V:3 - Vccp1 SENSORS_DS1780_IN1 Vccp1:3 - 3.3V SENSORS_DS1780_IN2 3.3V:3 - 5V SENSORS_DS1780_IN3 5V:3 - 12V SENSORS_DS1780_IN4 12V:3 - Vccp2 SENSORS_DS1780_IN5 Vccp2:3 - 2.5V_min SENSORS_DS1780_IN0_MIN 2.5V:1 - Vccp1_min SENSORS_DS1780_IN1_MIN Vccp1:1 - 3.3V_min SENSORS_DS1780_IN2_MIN 3.3V:1 - 5V_min SENSORS_DS1780_IN3_MIN 5V:1 - 12V_min SENSORS_DS1780_IN4_MIN 12V:1 - Vccp2_min SENSORS_DS1780_IN5_MIN Vccp2:1 - 2.5V_max SENSORS_DS1780_IN0_MAX 2.5V:2 - Vccp1_max SENSORS_DS1780_IN1_MAX Vccp1:2 - 3.3V_max SENSORS_DS1780_IN2_MAX 3.3V:2 - 5V_max SENSORS_DS1780_IN3_MAX 5V:2 - 12V_max SENSORS_DS1780_IN4_MAX 12V:2 - Vccp2_max SENSORS_DS1780_IN5_MAX Vccp2:2 - fan1 SENSORS_DS1780_FAN1 fan1:2 - fan2 SENSORS_DS1780_FAN2 fan2:2 - fan1_min SENSORS_DS1780_FAN1_MIN fan1:1 - fan2_min SENSORS_DS1780_FAN2_MIN fan2:1 - temp SENSORS_DS1780_TEMP temp:3 - temp_hyst SENSORS_DS1780_TEMP_HYST temp:2 - temp_over SENSORS_DS1780_TEMP_OVER temp:1 - vid SENSORS_DS1780_VID vid:1 - fan1_div SENSORS_DS1780_FAN1_DIV fan_div:1 - fan2_div SENSORS_DS1780_FAN2_DIV fan_div:2 - alarms SENSORS_DS1780_ALARMS alarms:1 - analog_out SENSORS_DS1780_ANALOG_OUT analog_out:1 - - -Chip `lm81' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - 2.5V NONE NONE R 2 - Vccp1 NONE NONE R 2 - 3.3V NONE NONE R 2 - 5V NONE NONE R 2 - 12V NONE NONE R 2 - Vccp2 NONE NONE R 2 - 2.5V_min 2.5V 2.5V RW 2 - Vccp1_min Vccp1 Vccp1 RW 2 - 3.3V_min 3.3V 3.3V RW 2 - 5V_min 5V 5V RW 2 - 12V_min 12V 12V RW 2 - Vccp2_min Vccp2 Vccp2 RW 2 - 2.5V_max 2.5V 2.5V RW 2 - Vccp1_max Vccp1 Vccp1 RW 2 - 3.3V_max 3.3V 3.3V RW 2 - 5V_max 5V 5V RW 2 - 12V_max 12V 12V RW 2 - Vccp2_max Vccp2 Vccp2 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - alarms NONE NONE R 0 - analog_out NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - 2.5V SENSORS_ADM9240_IN0 2.5V:3 - Vccp1 SENSORS_ADM9240_IN1 Vccp1:3 - 3.3V SENSORS_ADM9240_IN2 3.3V:3 - 5V SENSORS_ADM9240_IN3 5V:3 - 12V SENSORS_ADM9240_IN4 12V:3 - Vccp2 SENSORS_ADM9240_IN5 Vccp2:3 - 2.5V_min SENSORS_ADM9240_IN0_MIN 2.5V:1 - Vccp1_min SENSORS_ADM9240_IN1_MIN Vccp1:1 - 3.3V_min SENSORS_ADM9240_IN2_MIN 3.3V:1 - 5V_min SENSORS_ADM9240_IN3_MIN 5V:1 - 12V_min SENSORS_ADM9240_IN4_MIN 12V:1 - Vccp2_min SENSORS_ADM9240_IN5_MIN Vccp2:1 - 2.5V_max SENSORS_ADM9240_IN0_MAX 2.5V:2 - Vccp1_max SENSORS_ADM9240_IN1_MAX Vccp1:2 - 3.3V_max SENSORS_ADM9240_IN2_MAX 3.3V:2 - 5V_max SENSORS_ADM9240_IN3_MAX 5V:2 - 12V_max SENSORS_ADM9240_IN4_MAX 12V:2 - Vccp2_max SENSORS_ADM9240_IN5_MAX Vccp2:2 - fan1 SENSORS_ADM9240_FAN1 fan1:2 - fan2 SENSORS_ADM9240_FAN2 fan2:2 - fan1_min SENSORS_ADM9240_FAN1_MIN fan1:1 - fan2_min SENSORS_ADM9240_FAN2_MIN fan2:1 - temp SENSORS_ADM9240_TEMP temp:3 - temp_hyst SENSORS_ADM9240_TEMP_HYST temp:2 - temp_over SENSORS_ADM9240_TEMP_OVER temp:1 - vid SENSORS_ADM9240_VID vid:1 - fan1_div SENSORS_ADM9240_FAN1_DIV fan_div:1 - fan2_div SENSORS_ADM9240_FAN2_DIV fan_div:2 - alarms SENSORS_ADM9240_ALARMS alarms:1 - analog_out SENSORS_ADM9240_ANALOG_OUT analog_out:1 - - - - -Old Documentation ------------------ - -Supports the Analog Devices ADM9240 and the Dallas Semiconductor DS1780. -These chips are apparently identical except for the manufacturer ID -register. -The proc directory will be adm9240-i2c-x-xx for the adm9240 and -ds1780-i2c-x-xx for the ds1780. - ------------------------------------------------------------------------ - -This file documents the adm9240 directories for the Analog Devices -ADM9240 hardware health monitoring chip found on some Intel mainboards -(and others?). - -There will be one directory created for each detected ADM9240 chip. -Each chip must be on the SMBus. Directories are called things -like adm9240-i2c-1-2c. /proc/sys/dev/sensors/chips contains the SYSCTL -values for all chip directories. - -Within each ADM9240 directory, you can find the following files: -* alarms (ADM9240_SYSCTL_ALARMS) - A number which indicates which alarms are on. An alarm gets triggered when - some limit has been crossed. This number is composed from a 16 bit - value which is the combination of the Interrupt Status Register 1 - (low byte) and 2 (high byte). - This file can not be written to. - The number is the logical OR of the following components (bit # - followed by a description): - -0 +2.5 V_Error Read Only A "1" indicates a high or low limit has been exceeded. -1 VCCP_Error Read Only A "1" indicates a high or low limit has been exceeded. -2 +3.3 V_Error Read Only A "1" indicates a high or low limit has been exceeded. -3 +5 V_Error Read Only A "1" indicates a high or low limit has been exceeded. -4 Temp_Error Read Only A "1" indicates that a temperature interrupt has been set. -5 Reserved Read Only Undefined. -6 FAN1_Error Read Only A "1" indicates that a fan count limit has been exceeded. -7 FAN2_Error Read Only A "1" indicates that a fan count limit has been exceeded. -8 +12 V_Error Read Only A "1" indicates a high or low limit has been exceeded. -9 VCCP2_Error Read Only A "1" indicates a high or low limit has been exceeded. -10 Reserved Read Only Undefined. -11 Reserved Read Only Undefined. -12 Chassis_Error Read Only A "1" indicates chassis intrusion has gone high. -13 Reserved Read Only Undefined. -14 Reserved Read Only Undefined. -15 Reserved Read Only Undefined. - - If accessed through sysctl, this value is a long. -* fan[1-3] (ADM9240_SYSCTL_FAN[1-2]) - A list of two numbers. The first is the minimum fan rotation limit; the - second is the current fan rotation speed. Both are in RPM (rotations per - minute). An alarm is triggered if the rotation speed drops below the - limit. The first value can be changed. Not all RPM values can accurately - be represented, so some rounding is done. - If accessed through sysctl, this is a list of longs. -* fan_div (LM78_SYSCTL_FAN_DIV) - A list of two numbers, one for each fan. Each number can be either 1, 2, - 4 or 8. It is the internal scaling factor used for the fan rotations. If - you change this number, the fan readings get more or less detailed, but - the range in which they can be read too. Higher numbers give better - resolution, but less range. The first two numbers can be changed, the - third not. - If accessed through sysctl, this is a list of longs. -* 2.5V, Vccp1, 3.3V, 5V, 12V, and Vccp2 (ADM9240_SYSCTL_IN[0-5] in the - order shown) - A list of three numbers. The first is the minimum limit, the second is the - maximum limit, and the third is the current value. Note that - minimum means 'closest to zero'; so if the normal value equals -10, a - minimum could equal -9, and a maximum -11. Vccp1 and Vccp2 reflect core - voltages; they are by default set from the vid values, or set to 2.80V - if the vid lines seem to be unconnected. Not all voltage values - can be accurately represented, so some rounding is done. - The first two numbers can be changed, the third not. - If accessed through sysctl, this is a list of longs, each being the voltage - times 100. -* temp - A list of three numbers. The first number is the Overtemperature Shutdown - value; the second is the Hysteresis value and the third number is the - current value. The first two values can be modified. All values are in - degrees Celsius. An alarm is issued when the temperature first gets above - the Overtemperature Shutdown value; no more alarms are issued until the - temperature gets below the Hysteresis value, at which moment another alarm - is issued, and the state is reset. A more useful behaviour can be found - by setting the Hysteresis value to +127 degrees Celsius; in this case, - alarms are issued during all the time when the actual temperature is - above the Overtemperature Shutdown value. - The first two numbers can be changed, the third not. - If accessed through sysctl, this is a list of longs, each being the - temperature in degrees Celsius times 10. -* vid - The core voltage value (the voltage level your processor should work with), - in volts. This is the value IN0 and IN1 are initialized to. If unconnected, - it usually reads 3.50V. - This number can not be changed. - If accessed through sysctl, this is a long, being the voltage times 100. -* analog_out - This is feature is specific to the ADM9240. It is a DAC voltage - control register for the Analog-Out pin. Valid values are from 255 - to 0 (with 255 being the highest voltage, and 0 the lowest). From - the docs: "The ADM9240 has a single analog output from an unsigned - 8-bit DAC which produces 0 V - 1.25 V." - -The data for each ADM9240 is updated each 1.5 seconds, -but only if it is actually read. - -Note: Much of this documentation is copied from the LM78 documenation -(the device from which most featuers of the ADM9240 is modelled from). -The maintainer of the ADM9240 is Philip Edelbrock -; please forward corrections, suggestions, etc. -to him. For further technical information on this chip, I suggest -getting the Acrobat PDF documentation from www.analog.com. - -Dallas documentation is at http://www.dalsemi.com. diff --git a/doc/chips/asb100 b/doc/chips/asb100 deleted file mode 100644 index ab099b68..00000000 --- a/doc/chips/asb100 +++ /dev/null @@ -1,89 +0,0 @@ -Kernel driver `asb100.o' -======================== - -Status: Work in progress - -Supported Chips: - * Asus ASB100 and ASB100-A "Bach" - Prefix: 'asb100' - Addresses scanned: I2C 0x2d - Datasheet: none released - -Author: Mark M. Hoffman - -Module Parameters ------------------ - - - -Asus' BIOS is often broken --------------------------- - -If you have an Asus P4PE, you need to read prog/hotplug/README.p4b. - -If you have any other (Asus) board for which sensors-detect finds neither -asb100 nor an I2C bus, please read prog/hotplug/README.p4b before sending -a bug report. - -Description ------------ - -This driver implements support for the Asus ASB100 and ASB100-A "Bach". These -are custom ASICs available only on Asus mainboards. Asus refuses to supply a -datasheet for these chips. Thanks go to many people who helped investigate -their hardware, including: - -Vitaly V. Bursov -Alexander van Kaam (author of MBM for Windows) -Bertrik Sikken - -The ASB100 implements seven voltage sensors, three fan rotation speed sensors, -four temperature sensors, VID lines and alarms. In addition to these, the -ASB100-A also implements a single PWM controller for fans 2 and 3 (i.e. one -setting controls both.) If you have a plain ASB100, the pwm controller will -simply not work (or maybe it will for you... it doesn't for me). - -Temperatures are measured and reported in degrees Celsius. - -Fan speeds are reported in RPM (rotations per minute). An alarm is triggered -if the rotation speed has dropped below a programmable limit. - -Voltage sensors (also known as IN sensors) report values in volts. - -The VID lines encode the core voltage value: the voltage level your processor -should work with. This is hardcoded by the mainboard and/or processor itself. -It is a value in volts. - -Alarms: (TODO question marks indicate may or may not work) - -0x0001 => in0 (?) -0x0002 => in1 (?) -0x0004 => in2 -0x0008 => in3 -0x0010 => temp1 (1) -0x0020 => temp2 -0x0040 => fan1 -0x0080 => fan2 -0x0100 => in4 -0x0200 => in5 (?) (2) -0x0400 => in6 (?) (2) -0x0800 => fan3 -0x1000 => chassis switch -0x2000 => temp3 - -Alarm Notes: - -(1) This alarm will only trigger if the hysteresis value is 127C. -I.e. it behaves the same as w83781d. - -(2) The min and max registers for these values appear to -be read-only or otherwise stuck at 0x00. - -TODO: -* Experiment with fan divisors > 8. -* Experiment with temp. sensor types. -* Are there really 13 voltage inputs? Probably not... -* Fix bogus client deregistration (like w83781d in 2.6). -* Fix fan divisor / fan minimum interaction (like lm78). -* Cleanups, no doubt... - diff --git a/doc/chips/bmcsensors b/doc/chips/bmcsensors deleted file mode 100644 index b2aac3a1..00000000 --- a/doc/chips/bmcsensors +++ /dev/null @@ -1,140 +0,0 @@ -Kernel driver `bmcsensors.o' -========================== - -Status: Alpha - -Supported chips: - * IPMI BMC - Prefix: 'bmc' - Requires dummy adapter i2c-ipmi; - Driver will be registered as bmc-ipmi-0000. - -Author: M. Studebaker - -License: GPL - - -Module Parameters ------------------ - -None. - - -Detection ---------- - -Registers only with i2c-ipmi. - - -Description ------------ - -Together with the i2c-ipmi module, this provides high-level -access to sensors known by the BMC. For low-level access to -IPMB (I2C/SMBus) busses behind the BMC, use the i2c-ipmb module -and individual chip drivers. - -This module REQUIRES the IPMI kernel patch by Corey Minyard, -v13 or higher, available at http://openipmi.sourceforge.net . -Other IPMI drivers are not supported. - -See http://www.intel.com/design/servers/ipmi/ for -IPMI standards information. - -You must configure the following features in your kernel -(under Character Devices): - IPMI top-level message handler - IPMI KCS handler -The IPMI device interface and IPMI watchdog handler are not required. - -You must modprobe i2c-ipmi separately, it will not -load automatically when you modprobe bmcsensors. - -If the KCS handler (ipmi_kcs_drv) is configured as a module, -you must also modprobe it separately, it will not load automatically -when you modprobe i2c-ipmi or ipmi_msghandler (unless you set up -/etc/modules.conf to load ipmi_kcs_drv when ipmi_msghandler is loaded). - - -/proc entries -------------- - -The BMC SDR's (Sensor Data Records) are scanned and -the /proc table is built dynamically. Sensor types and quantities -depend on what the BMC supports. - - curr1-n Currents. Max, min, and reading in amps. - fan1-n Fan speeds. Min and reading in RPM. - in1-n Voltages. Max, min, and reading in volts. - temp1-n Temps. Max, hysteresis or min, and reading in degrees C. - -Thresholds will appear as 0 if unsupported or unreadable, as indicated -in the SDR. - -If the thresholds are not settable (as indicated in the SDR), the -/proc permissions for that sensor will be 444. - -After the SDR's are scanned, the module will print -the sensor names and bindings to syslog/dmesg. -Cut these messages out and paste them to /etc/sensors.conf -so that 'sensors' has correct labeling. - - -Issues ------- -The module will not register in /proc/sys/dev/sensors until -the SDR's are scanned. This may take several seconds. - -The driver uses a very simple state machine. It only sends -one message at a time and then waits for a response. -This makes the driver relatively slow. -If a response is an error or does not arrive, the driver -will probably be stuck. - -/proc access kicks off an update but returns the old data, -not the new; need to wait for update to finish and then return. - -Probably there are some locking issues. - -Every attempt is made to present the sensor data in /proc in a -manner consistent with lm_sensors /proc standards, as defined -in doc/developers/proc. Given the wide variation in possible SDR definitions, -this may not generate expected or useful data. - -IPMI supports up to 4 max and 4 min thresholds (non-recoverable, critical, -non-critical, and hysteresis) for each sensor. This driver -tries to pick out the best one and exports it as the max and min -to /proc. - -ins start at 1, other modules start at in0. - -Alarms and thresholds are not yet supported. - -Threshold-only sensors are not supported. - -Threshold setting is not yet supported. - -1's and 2's complement formats not yet supported. - -Non-linear conversions not supported, except for 1/x. - -Fan divs are not supported (or required) - should the driver -export a fan_div entry (1 1 1 ...) for compatibility? - -Supports only sensor types 1-4 (temp, voltage, current, and fan). - -Libsensors can't handle dynamic /proc entries so the table -in lib/chips.c must be static and contain the max number of -each sensor. Bmcsensors can register more of a sensor type -than libsensors supports in its static table. - -Only one BMC is supported - shouldn't be a problem. - -Alpha! - - - - -********************** -The lm_sensors project gratefully acknowledges the support of -Hewlett Packard (Ft. Collins) in the development of this driver. diff --git a/doc/chips/bt869 b/doc/chips/bt869 deleted file mode 100644 index 9a3b1470..00000000 --- a/doc/chips/bt869 +++ /dev/null @@ -1,397 +0,0 @@ -Kernel driver `bt869.o' -====================== - -Status: 'Beta' and needs further development and testing - -Supported chips: - * Brooktree BT869 Video Modulator chips - Prefix: 'bt869' - Addresses scanned: I2C 0x44 - 0x45 - Datasheet: Publicly available at the brooktree web site - (www.brooktree.com) - -Author: Frodo Looijaard , Philip Edelbrock - , Ralph Metzler - Steve Davies added the 720x576 and - 720x480 support, and the svideo configuration. - -Main Contact: Philip Edelbrock - -Module Parameters ------------------ -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_bt869: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `bt869' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This driver provides some access to the Brooktree bt869 found on some -video cards (like the 'Voodoo3 3000'). Typically, the output can be -either an s-video connection or composite video. Resolutions -supported using the chip's built in configurations are 640x480 or -800x600. In addition, a 720x576 PAL mode and a 720x480 NTSC mode, -both without overscan compensation, are supported - a convenient -configuration for video playback. - -Other possible implementations may allow for double resolutions with some -decimations (e.g., a monitor running at 1280x960 but the TV out getting every -other pixel for 640x480). - - -Driver Features ---------------- -Standards: (US) NTSC or PAL -Resolutions: 640x480, 800x600, 720x576 (PAL only), 720x480 (NTSC only) -Depths: 16, 24 or 32 bits -Colorbars: Switch on the built-in color bar generator. (FYI- using a blue -filter, you should see only alternating bright stripes of equal brightness. -Adjust your TV's color and saturation if this isn't the case.) -SVideo: composite or s-video output. Also, theoretically, RGB output, though -this isn't tested and will require that your card presents all three DAC outputs -(the 3dfx Voodoo3 doesn't) - -In your XF86Config file, you should have these entries for NTSC output: - -ModeLine "640x480NTSC" 28.195793 640 656 658 784 480 520 525 600 -ModeLine "720x480NTSC" 27.5 720 744 800 872 480 483 485 525 -ModeLine "800x600NTSC" 38.769241 800 812 814 880 600 646 649 735 - -or for PAL - -ModeLine "640x480PAL" 29.50 640 675 678 944 480 530 535 625 -ModeLine "720x576PAL" 27.50 720 744 800 880 576 581 583 625 -ModeLine "800x600PAL" 36.00 800 818 820 960 600 653 655 750 - -Also, don't forget to add these modes to the resolutions list in the -'screen' sections of XF86Config. You can change modes on the fly in X by -pressing (usually) ctrl-alt-+ or ctrl-alt-(minus) with + and - being the -keys on your numeric 10-key pad. - -BTW- My monitor doesn't like these entries very much, and as I've read: -don't run your monitor out of spec or else it will burst into fire. So, -having the monitor turned on while in any of these modes is at your own -risk. (I've never heard of a monitor breaking from this, but it seems to -be fashionable to warn about it.) - - -Chip Features -------------- -The chip is very flexible and customizable for many standards. Right -now the driver sticks with the chip's built in NTSC and PAL standards, -with the addition of the 720x576PAL and 720x480NTSC modes. It also -does some other wacky stuff like closed-captioning, Macro-vision -copy-protection, and other things. Check out the datasheet for more -info. - - -Issues ------- -The depth register doesn't seem to do much? If you have troubles or -aren't sure the output is working, turn the color-bars on. If they display -OK, then the chip is syncing correctly. The next thing to try is the depth -setting. Lastly, turning off your computer and back on with your TV -connected but you monitor not, may force the video card to configure and -use the BT869 as your primary output device (all bets are off once X is -started). Let me know if you have problems which you can't figure out -(phil@netroedge.com). - --------------------------------- - -On May 3rd, 2001 (My birthday, as it happens to be :') Tomi Ollila sent me -a how-to from a user's perspective on using the BT869 with a 3Dfx card. -It should also provide insight for other video card users who have a -BT869 on board. Here is his document: - - -How-To ------- - - -This text describes my successful attempt to eventually get the TV-Out -feature of 3DFX Voodoo 3 3000 (PAL) working in a Linux environment. -I've successfully configured the 800x600 mode -- And currently I am -not interested in 640x480 -- hardware scaling rules in all cases -I need the tv-out. My monitor works much less worse w/ 800x600PAL... - -All the information is based on my best knowledge but there might be -some mistakes. In any case, THE ENTIRE RISK OF USING THIS INFORMATION -IS WITH YOU, AND NO ONE ELSE IS LIABLE OF ANY PROBLEMS ENCOUNTERED. -Please fix any mistakes, inaccuracies, writing errors, etc. you -notice in this document. - -I was about to write briefly, but sorry due to limited resources -I did not have time to write briefly (too much thinking ;). -Well, browse through the text and skip all irrelevant parts -to proceed... - -Tomi Ollila - - -The first time I got the the tv-out working I was working w/ Linux kernel -2.4.3. Now I am redoing the work w/ Linux 2.4.4 and recording the steps -in this document. Description of my system and software used is as follows: - -RedHat 7.0 linux distribution (probably any distribution will do, since -all of the needed software is compiled from packages that are not RH-pagkaged) -(maybe if anything is important, are modutils-2.3.14-3 and kernel-headers-2.4.0-0.26) - -XFree-4.0.3. I don't see any reason anyone uses any older. HW acceleration -of Voodoo3 3000 works out of the box with this. Also Windowed!!! - -lm_sensors-2.5.5: Get this or newer. I have not used any older. - -i2c-2.5.5: Probably 2.4.x -kernel distributions has recent enough version -of i2c. Since I also have IOmega BUZ and it's (working) versions require -i2c-old, I cannot use the one's kernel provided. Since I cannot say anything -about not using this i2c as separate package I suggest you do the same -and compile this also. - -I have used kgcc that comes in RedHat 7.0 -distribution to compile all -stuff. Probably all other recent gcc -compilers will produce good results -also: kgcc -v outputs: -Reading specs from /usr/lib/gcc-lib/i386-glibc21-linux/egcs-2.91.66/specs -gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release) - --- - -1) The work starts w/ kernel compilation (or skip to step 2, I quess it will - work w/ any recent 2.2 and 2.4 -kernels) - - # run make config, make menuconfig or make xconfig (I suggest 'xconfig') - - For sure you need kernel module support and /proc -filesystem support - (XXX add more absolute requirements) - - Now I cannot say for sure, if following things needs to be compiled - at kernel compilation time or does i2c-2.5.5 bring all these: - character devices->i2c support->i2c support - character devices->i2c support->i2c bit-banging interfaces (*) - character devices->i2c support->i2c devices (**) - character devices->/dev/agpart support - character devices->Direct Rendering Manager (XFree86 DRI support) (+) - character devices->3dfx banshee/Voodoo3+ - - make above as modules. - - (*) I already forgot why I wanted some special attention for this - (**) It seems I never need this - (+) Hmm, It seems I have compiled this as part of the kernel binary - - There is of course lot of other options you need to choose but these - are probably the ones needed... - - # run make dep - # run make bzImage - # run make modules - # run make modules_install (as root) - # copy arch/i386/boot/bzImage to /boot/vmlinuz-2.4.4 (as root) - # edit /etc/lilo.conf and run lilo (as root) - -2) In order to (the most easiest way) compile separate i2c and lm_sensors - -package, symlink your linux source tree to /usr/src/linux (unless it is - there already) and do the following - - # tar zxvf i2c-2.5.5.tar.gz - # cd i2c-2.5.5 - # make - # make install (as root) - # cd .. - # tar zxvf lm_sensors-2.5.5.tar.gz - # cd lm_sensors-2.5.5 - # make - # make install (as root) - # cd .. - - Now you have all necessary modules installed on the system (and - /usr/local/bin/sensors and /usr/local/sbin/sensors-detect). - - But there is some configuration missing in order to activate - the needed functionality of the modules... - -3) Now, before going any further, let's take a look the modifications that - is required in XFree86 -configuration so that X is ready for the - tv-out functionality next time it is started. - - XFree86-4.x uses the configuration file /etc/X11/XF86Config-4. Older - configuration files needed "ModeLine"s for all display resolutions - that are needed, but XFree86 version 4 can figure out those by itself. - But what it cannot figure out, are some special ModeLines that may - be reguired in various cases... and this is one of these. - - For Voodoo 3 3000 TV out feature, special modelines are needed for - the supported resolutions, 640x480 and 800x600 (there might be others - but I don't know enough of the issue. In this document, I only - activate the 800x600 mode. - - Make backup copy of your /etc/X11/XF86Config-4 in case you accidentally - screw something up so you can then reuse the old file if this happens. - - Open /etc/X11/XF86Config-4 in your favourite editor and find line - that contains `Section "Monitor"'. At the end of that section, - just before line `EndSection', add the following lines: - -ModeLine "640x480PAL" 29.50 640 675 678 944 480 530 535 625 -ModeLine "800x600PAL" 36.00 800 818 820 960 600 653 655 750 - - Then, find lines that starts with something like: - -Section "Screen" - Identifier "Screen0" - Device "3Dfx Interactive, Inc.|Voodoo 3" - Monitor "" - DefaultDepth 16 -... - Subsection "Display" - Depth 16 -# Modes "1024x768" "640x480" "800x600" "800x600PAL" #"400x300" - Modes "1024x768" "800x600PAL" - EndSubSection - - Make sure that `DefaultDepth' is set 16 (I don't know if any other works) - Then you notice there my resolutions as `Modes' -lines. I have outcommented - the first `Modes' -line so that testing is easier. You can do what - you widh here, just make sure to add that `"800x600PAL"' -line there. - Save the file and exit editor. - - -4) It's is time to reboot (with new kernel), that is the easiest way to - continue. - -5) After rebooting, and X startup `lsmod' in my machine output following: - Module Size Used by - tdfx 54536 1 - es1371 28500 0 - ac97_codec 8808 0 [es1371] - - tdfx -module was loaded by X, and sound module by some RH -startup script. - - Now you could run /usr/local/sbin/sensors-detect. After that was run in - my PII class -machine it suggested I add the following: - - to /etc/modules.conf - alias char-major-89 i2c-dev - - to some startup script (i choose append to /etc/rc.local) - # I2C adapter drivers - /sbin/modprobe i2c-piix4 - /sbin/modprobe i2c-voodoo3 - # I2C chip drivers - /sbin/modprobe w83781d - /sbin/modprobe eeprom - - (you run the prg and add the stuff it suggests) - - Let's now /sbin/modprobe -v i2c-voodoo3. Now I have: - - Module Size Used by - i2c-voodoo3 3012 0 (unused) - i2c-algo-bit 7796 2 [i2c-voodoo3] - i2c-core 12844 0 [i2c-algo-bit] - tdfx 54536 1 - es1371 28500 0 - ac97_codec 8808 0 [es1371] - - I think this is the only one of the above that is required for the task. - (If that is not true, I'll revise this text and you never know I though - such a thing) - - Now, turn on your TV set (unless it is already open) and make sure it - is getting (either s-video or composite... I personally have only - tested composite) input from your voodoo3 card. Don't change any - screen resolution just yet... - - You notice the tv set screen is still blank. Changing screen resolutions - won't do any change on that, don't bother trying. - - So, how to continue from there. The answer was found looking through - all the files that are found with zsh command line in lm_sensors dir: - grep -i voodoo3 **/*(.) | less - The file doc/chips/bt869 contains interesting information, with it - and some other information I found somewhere else, don't remember - either, I did: - - modprobe -v bt869 (or insmod /lib/modules/2.x.x/misc/bt869) - - NOW! you should see some noise on your TV-Set screen. - - and `lsmod' returns (on my machine) - - Module Size Used by - bt869 5392 0 (unused) - i2c-voodoo3 3012 0 (unused) - sensors 6140 0 [bt869] - i2c-algo-bit 7796 2 [i2c-voodoo3] - i2c-core 12844 0 [bt869 sensors i2c-algo-bit] - tdfx 54536 1 - es1371 28500 0 - ac97_codec 8808 0 [es1371] - - If you now try to change mode to `800x600PAL' The noise pattern just - changes. That's because there are various parameters for bt869 to - make it operate in different systems. - - The configuration entries for bt869 live somewhere in `proc' filesystem - and since it is so hard to remember, the following commands helps out: - - # find /proc -name "bt869*" -print - - In my system that output: /proc/sys/dev/sensors/bt869-i2c-0-44. Since - the last few characters may be different on your system I'll use... - - # ls /proc/sys/dev/sensors/bt869* ... and this outputs: - - colorbars: Output colorbars instead of display data. Default `0'. - depth: Display depth. Seems to be `16' on my system. - half: No idea. Default `0'. - ntsc: 1: use NTSC, 0: use PAL. Default: `1'. - res; Screen resolution to use. Defaut: `640 480'. - status: Outputs some status info I do not know what that is. - - For me, in order to get TV sync with incoming signal (or is it Voodoo3 - that needs syncing), I first put colorbars on, and when I get colorbars - visible I shut colorbars off -- and then I have part of my 1024x768 - displayed on TV-screen. Normal WIMP screen doesn't look so nice, but - games, pictures, etc. Looks just fine. And HW acceleration rules. - - Do the following to achieve this: - - # echo 1 > /proc/sys/dev/sensors/bt869*/colorbars - # echo 0 > /proc/sys/dev/sensors/bt869*/ntsc - # echo 800 600 > /proc/sys/dev/sensors/bt869*/res - - Press ctrl-alt-num_keypad_+ - - Now you should see vertical colorbars on your TV-Set - - # echo 0 > /proc/sys/dev/sensors/bt869*/colorbars - - Now (part of) your computer display should be visible on your TV-Set. - - - ... Ok, I did just that... after ctrl-alt-num_keypad_+ I did not get - synchronized colorbar output visible on my TV. So, at this time I - re-did... - - # echo 1 > /proc/sys/dev/sensors/bt869*/colorbars - - ... and got colorbars, and ... - - # echo 0 > /proc/sys/dev/sensors/bt869*/colorbars - - ... got my computer display visible on my TV. - - -#EOF - diff --git a/doc/chips/ddcmon b/doc/chips/ddcmon deleted file mode 100644 index 63ef0aa3..00000000 --- a/doc/chips/ddcmon +++ /dev/null @@ -1,272 +0,0 @@ -Kernel driver `ddcmon.o' -======================== - -Status: As complete as we want it to be, lightly tested - -Supported chips: - * Any DDC Monitor EDID EEPROM chip at 0x50 - Prefix: 'ddcmon' - Addresses scanned: I2C 0x50 - Standards: available for purchase from VESA http://www.vesa.org - Datasheets: Publicly available from Atmel (www.atmel.com), - Fairchild (www.fairchildsemi.com), and - Microchip (www.microchip.com) - - Chip Size (bits) Address - 24C01 1K 0x50 (shadows at 0x51 - 0x57) - (Typical device in monitors) - 24C01A 1K 0x50 - 0x57 (Typical device in monitors) - 24C02 2K 0x50 - 0x57 - 24C04 4K 0x50, 0x52, 0x54, 0x56 - (additional data at 0x51, 0x53, 0x55, 0x57) - 24C08 8K 0x50, 0x54 (additional data at 0x51, 0x52, - 0x53, 0x55, 0x56, 0x57) - 24C16 16K 0x50 (additional data at 0x51 - 0x57) - - -Author: Frodo Looijaard , Philip Edelbrock - , Mark Studebaker and - Jean Delvare - -Special assistance on DDC provided by Petr Vandrovec - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_ddcmon: short array (min = 1, max = 48) - Same as 'force' -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* checksum: int - Only accept eeproms whose checksum is correct - - -Description ------------ - -This is a simple module for reading the EEPROM on a DDC-compliant monitor. -DDC (Display Data Channel) is the I2C-based communication channel -to the monitor. The EEPROM contains a 128-byte data structure defined -by the EDID (Extended Display Identification Data) standard. - -Use: - -After inserting the module (and any other required smbus/i2c modules), you -should have a directory in /proc/sys/dev/sensors/ with a name such -as "ddcmon-i2c-3-50". Inside each of these is a series of files which -represent interesting data from the DDC monitor. - -/proc entries: - - dpms: bitmask - DPMS support flags - 0x20 Active Off - 0x40 Suspend - 0x80 Standby - - edid: 2 integers - EDID version and revision - - gamma: 1 float - gamma factor - - id: 2 integers - manufacturer ID and product ID - Manufacturer ID is encoded, see 'sensors' - source ../../prog/sensors/chips.c. - - maxclock: 1 integer - max pixel clock (also known as video bandwidth) (MHz) - 0 if not available. - - serial: 1 integer - serial number - Encoding depends on the manufacturer, don't expect the - real serial number here. 0 probably means "not available". - - size: 2 integers - vertical monitor size (cm) - horizontal monitor size (cm) - - sync: 4 integers - minimum vertical sync frequency (Hz) - maximum vertical sync frequency (Hz) - minimum horizontal sync frequency (KHz) - maximum horizontal sync frequency (KHz) - 0 0 0 0 if not available. - - time: 2 integers - Manufacture year and week - - timing[1-8]: 3 integers - supported standard timing - horizontal resolution - vertical resolution - (vertical) refresh rate - 0 0 0 if not used. - - timings: bitmask - supported established timings - 0x000001 720x400@70Hz (VGA 640x400, IBM) - 0x000002 720x400@88Hz (XGA2) - 0x000004 640x480@60Hz (VGA) - 0x000008 640x480@67Hz (Mac II, Apple) - 0x000010 640x480@72Hz (VESA) - 0x000020 640x480@75Hz (VESA) - 0x000040 800x600@56Hz (VESA) - 0x000080 800x600@60Hz (VESA) - 0x000100 800x600@72Hz (VESA) - 0x000200 800x600@75Hz (VESA) - 0x000400 832x624@75Hz (Mac II) - 0x000800 1024x768@87Hz interlaced (8514A) - 0x001000 1024x768@60Hz (VESA) - 0x002000 1024x768@70Hz (VESA) - 0x004000 1024x768@75Hz (VESA) - 0x008000 1280x1024@75Hz (VESA) - 0x010000 - 0x800000 Manufacturer reserved - 0x800000 1152x870 @ 75 Hz (Mac II, Apple)? - - -Chip Features -------------- - -Chip 'ddcmon' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -Manufacturer ID - - R- 0 -Model Number - - R- 0 -Monitor Size (cm) - - R- 0 -hsize Monitor Size (cm) - R- 0 -Vertical Sync (Hz) - - R- 0 -v_sync_max Vertical Sync (Hz) - R- 0 -Horizontal Sync (KHz) - - R- 0 -h_sync_max Horizontal Sync (KHz) - R- 0 -Established Timings - - R- 0 -Serial Number - - R- 0 -Manufacture Time - - R- 0 -week Manufacture Time - R- 0 -EDID Version - - R- 0 -revision EDID Version - R- 0 -Gamma Factor - - R- 2 -DPMS Modes - - R- 0 -Standard Timing 1 - - R- 0 -vertical Standard Timing 1 - R- 0 -refresh Standard Timing 1 - R- 0 -Standard Timing 2 - - R- 0 -vertical Standard Timing 2 - R- 0 -refresh Standard Timing 2 - R- 0 -Standard Timing 3 - - R- 0 -vertical Standard Timing 3 - R- 0 -refresh Standard Timing 3 - R- 0 -Standard Timing 4 - - R- 0 -vertical Standard Timing 4 - R- 0 -refresh Standard Timing 4 - R- 0 -Standard Timing 5 - - R- 0 -vertical Standard Timing 5 - R- 0 -refresh Standard Timing 5 - R- 0 -Standard Timing 6 - - R- 0 -vertical Standard Timing 6 - R- 0 -refresh Standard Timing 6 - R- 0 -Standard Timing 7 - - R- 0 -vertical Standard Timing 7 - R- 0 -refresh Standard Timing 7 - R- 0 -Standard Timing 8 - - R- 0 -vertical Standard Timing 8 - R- 0 -refresh Standard Timing 8 - R- 0 -Max Pixel Clock (MHz) - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -Manufacturer ID SENSORS_DDCMON_MAN_ID id:1 -Model Number SENSORS_DDCMON_PROD_ID id:2 -Monitor Size (cm) SENSORS_DDCMON_VERSIZE size:1 -hsize SENSORS_DDCMON_HORSIZE size:2 -Vertical Sync (Hz) SENSORS_DDCMON_VERSYNCMIN sync:1 -v_sync_max SENSORS_DDCMON_VERSYNCMAX sync:2 -Horizontal Sync (KHz) SENSORS_DDCMON_HORSYNCMIN sync:3 -h_sync_max SENSORS_DDCMON_HORSYNCMAX sync:4 -Established Timings SENSORS_DDCMON_TIMINGS timings:1 -Serial Number SENSORS_DDCMON_SERIAL serial:1 -Manufacture Time SENSORS_DDCMON_YEAR time:1 -week SENSORS_DDCMON_WEEK time:2 -EDID Version SENSORS_DDCMON_EDID_VER edid:1 -revision SENSORS_DDCMON_EDID_REV edid:2 -Gamma Factor SENSORS_DDCMON_GAMMA gamma:1 -DPMS Modes SENSORS_DDCMON_DPMS dpms:1 -Standard Timing 1 SENSORS_DDCMON_TIMING1_HOR timing1:1 -vertical SENSORS_DDCMON_TIMING1_VER timing1:2 -refresh SENSORS_DDCMON_TIMING1_REF timing1:3 -Standard Timing 2 SENSORS_DDCMON_TIMING2_HOR timing2:1 -vertical SENSORS_DDCMON_TIMING2_VER timing2:2 -refresh SENSORS_DDCMON_TIMING2_REF timing2:3 -Standard Timing 3 SENSORS_DDCMON_TIMING3_HOR timing3:1 -vertical SENSORS_DDCMON_TIMING3_VER timing3:2 -refresh SENSORS_DDCMON_TIMING3_REF timing3:3 -Standard Timing 4 SENSORS_DDCMON_TIMING4_HOR timing4:1 -vertical SENSORS_DDCMON_TIMING4_VER timing4:2 -refresh SENSORS_DDCMON_TIMING4_REF timing4:3 -Standard Timing 5 SENSORS_DDCMON_TIMING5_HOR timing5:1 -vertical SENSORS_DDCMON_TIMING5_VER timing5:2 -refresh SENSORS_DDCMON_TIMING5_REF timing5:3 -Standard Timing 6 SENSORS_DDCMON_TIMING6_HOR timing6:1 -vertical SENSORS_DDCMON_TIMING6_VER timing6:2 -refresh SENSORS_DDCMON_TIMING6_REF timing6:3 -Standard Timing 7 SENSORS_DDCMON_TIMING7_HOR timing7:1 -vertical SENSORS_DDCMON_TIMING7_VER timing7:2 -refresh SENSORS_DDCMON_TIMING7_REF timing7:3 -Standard Timing 8 SENSORS_DDCMON_TIMING8_HOR timing8:1 -vertical SENSORS_DDCMON_TIMING8_VER timing8:2 -refresh SENSORS_DDCMON_TIMING8_REF timing8:3 -Max Pixel Clock (MHz) SENSORS_DDCMON_MAXCLOCK maxclock:1 - - -Notes ------ - -- The eeprom.o module will also attach to a DDC monitor. Install the - ddcmon.o module before the eeprom.o module to prevent this. - Alternatively, give the eeprom.o module an ignore= parameter or - a checksum= parameter. The ddcmon.o module will not attach to non-DDC - eeproms because it checks for a DDC 'signature' at the beginning - of the DDC Monitor's eeprom. Additionally, you can give it a checksum= - parameter. - -- If a DDC monitor eeprom lacks the 'signature', you may use the - 'force' parameter (modprobe ddcmon force=x,0x50 where 'x' is the - i2c bus number). - -- This module requires a bus driver for your video chip to access the - DDC bus. In this package, drivers exist for Voodoo3/Banshee chips. - See documentation for those drivers in ../busses. Other drivers - (Matrox and NVidia, for example) are available in the kernel or - elsewhere. See our 'Supported Devices' web page for details. - -- There is a checksum over the 128 bytes in the eeprom. The driver - used not to check it, now it does (providing you give it a - checksum= parameter). - -- More information is available in the eeprom which could be made - available by enhancing the driver. - To see the entire eeprom, use the eeprom.o module instead of ddcmon.o. - However, then you lose the DDC-specific formatting. - Also see ../../prog/eeprom/decode-edid.pl. - -- This driver does not support the DDC/CI (DDC2Bi) bidirectional - communications channel to the monitor for controlling the monitor. - -- The driver caches the data from the monitor and only rereads it - from the eeprom if the cache is more than 5 minutes old. - -- X 4.0 also accesses the DDC monitor EEPROM to auto-configure itself. - There could possibly be conflicts from these multiple accesses, but - none were ever reported so far. diff --git a/doc/chips/ds1307 b/doc/chips/ds1307 deleted file mode 100644 index 217c40ca..00000000 --- a/doc/chips/ds1307 +++ /dev/null @@ -1,25 +0,0 @@ -Kernel driver `ds1307.o' -======================== - -Status: Complete and well-tested - -Supported chips: - * Dallas Semiconductor DS1307 Real-time clock - -Author: Abraham vd Merwe - - -Module Parameters ------------------ - -There are no module parameters. The driver only scans address 0x68 for -presence of the real-time clock chip (which is the only possible address). - - -Description ------------ - -This module provides an API for drivers RTC and NVRAM drivers to use in -order to access the DS1307 real-time clock. Examples of drivers that uses -this API are the frodo-nvram and frodo-rtc drivers. - diff --git a/doc/chips/ds1621 b/doc/chips/ds1621 deleted file mode 100644 index 9cf89b4e..00000000 --- a/doc/chips/ds1621 +++ /dev/null @@ -1,237 +0,0 @@ -Kernel driver `ds1621.o' -======================== - -Status: Complete and tested; enhanced features experimental - -Supported chips: - * Dallas Semiconductor DS1621 - Prefix: 'ds1621' - Addresses scanned: I2C 0x48 - 0x4f - Datasheet: Publicly available at the Dallas Semiconductor website - http://www.dalsemi.com/ - * Dallas Semiconductor DS1625 - Prefix: 'ds1621' - Addresses scanned: I2C 0x48 - 0x4f - Datasheet: Publicly available at the Dallas Semiconductor website - http://www.dalsemi.com/ - -Author: Christian W. Zuckschwerdt -valueable contributions by Jan M. Sendler - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_ds1621: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to - contain a `ds1621' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -The DS1621 is a (one instance) digital thermometer and thermostat. It -has both high and low temperature limits which can be user defined -(i. e. programmed into non-volatile on-chip registers). -Temperature range is -55 degree Celsius to +125 in 0.5 increments. You -may convert this into a Fahrenheit range of -67 to +257 degrees with -0.9 steps. Unfortunally though, you will need a hash table or even a -conversion routine for that. - -Temperature readings are internally converted into a 9bit value to be -read straight via the i2c-bus, but higher resolutions may be obtained -with little effort via 'precise_temp' access or using a simple algorithm. - -As for the thermostat, behavior can also be programmed using the -polarity toggle. -On the one hand ("heater"), the thermostat output of the chip, Tout, -will trigger when the low limit temperature is met or underrun and -stays high until the high limit is met or exceeded. On the other hand -("cooler"), vice versa. -That way "heater" equals "active low", whereas "conditioner" equals -"active high". Please note that the DS1621 data sheet is somewhat -misleading in this point since setting the polarity bit does not -simply invert Tout. - - -A second thing is that, during extensive testing, Tout showed a -tolerance of up to +/- 0.5 degrees even when compared against precise -temperature readings. -Be sure to have a high vs. low temperature limit gap of al least 1.0 -degree Celsius to avoid Tout "bouncing", though! - -As for alarms, you can read the alarm status of the DS1621 via the -'alarms' proc file interface. The result consits mainly of bit 6 and 5 -of the configuration register of the chip; bit 6 (0x40 or 64) is the -high alarm bit and bit 5 (0x20 or 32) the low one. These bits are set -when the high or low limits are met or exceeded and are reset by the -module as soon as the respective temperature ranges are left. - -The alarm registers are in no way suitable to find out about the -actual status of Tout. They will only tell you about its history, -whether or not any of the limits have ever been met or exceeded since -last power-up or reset. Be aware: When testing, it showed that the -status of Tout can change with neither of the alarms set. - -Temperature conversion of the DS1621 takes up to 1000ms; internal -access to non-volatile registers may last for 10ms or below. - -This driver also detects DS1625. As this chip is discontinued, you -should use a DS1621 instead. Detected 1625s also get the -"ds1621"-prefix, but the accuracy registers are not supported. -The latest modification of this driver was not checked against 1625s, -though, but should work well with them. - -Default values written into the DS1621 upon detection are: -Temperature limits: High 60.0; low 0.0 degree Celsius; -Continuous mode (not enabled), Tout active high, alarms reset. - - -Accessing DS1621 via /proc interface (part I) ---------------------------------------------- - -On detection (i.e. insmod, modprobe et al.), directories are being -created for each detected DS1621: - -/proc/sys/dev/sensors/ds1621-<0>-<1>/ -where <0> is the bus the chip was detected on (e. g. i2c-0) -and <1> the chip address ([48..4f]): ./ds1621-i2c-0-48/ - -Inside these directories, there are five files each: -alarms, continuous, enable, polarity and temp. - -The temp, alarms and enable are LM75-like for compatibility reasons: - -The temp file is rw. Reading gives TEMP_HIGH:TEMP_HYST:TEMP, where -TEMP_HIGH is the upper limit temp, TEMP_HYST is the hysteresis (lower -limit) temp and TEMP is the actual temperature. (For things like -ONE_SHOT, see below.) - Writing takes two results (read: input -values): TEMP_HIGH:TEMP_HYST. This provides an easy way to set limits. - -The alarms file is ro. Basically, it is 0x40 ("64") for the high alarm -bit set plus 0x20 ("32") for the low one. Since alarms are being reset -by the module when the limit conditions are no longer met, you should -first read the alarms before you do anything else (such as reading the -temperature), or the information may be lost. - -The polarity file is rw. Reading gives "0" for active high, which -describes a need for cooling corresponds to Tout status. "1" means -active low, so you can connect a powerful heater directly to Tout -(DON'T TRY!). - Writing accepts "0" and "1" accordingly. Again, note -that the statements on page 5 of the DS1621 data sheet are misleading; -change the orientation of the vertical arrows in the sketch there -instead. - -To understand the use of the other things, it is useful to have a -brief look at the internal DS1621 procedures: - - -High Accuracy Temperature Reading ---------------------------------- - -As said before, the temperature issued via the 9bit i2c-bus data is -somewhat arbitrary. Internally, the temperature conversion is of a -different kind that is explained (not so...) well in the DS1621 data -sheet. To cut the long story short: Inside the DS1621 there are two -oscillators, both of them biassed by a temperature coefficient. - -Higher accuracy of the temperature reading can be achieved using the -internal projection, which means taking account of REG_COUNT and -REG_SLOPE (the driver manages them): - -Taken from Dallas Semiconductors App Note 068: 'Increasing Temperature -Resolution on the DS1620' and App Note 105: 'High Resolution -Temperature Measurement with Dallas Direct-to-Digital Temperature -Sensors' - -- Read the 9bit temperature and strip the LSB (Truncate the .5 degs) -- The resulting value is TEMP_READ. -- Then, read REG_COUNT. -- And then, REG_SLOPE. - - TEMP = TEMP_READ - 0.25 + ((REG_SLOPE - REG_COUNT) / REG_SLOPE) - -Note that this is what the DONE bit in the DS1621 configuration -register is good for: Internally, one temperature conversion takes up -to 1000ms. Before that conversion is complete you will not be able to -read valid things out of REG_COUNT and REG_SLOPE. The DONE bit, as you -may have guessed by now, tells you whether the conversion is complete -("done", in plain english) and thus, whether the values you read are -good or not. - -The DS1621 has two modes of operation: "Continuous" conversion, which -can be understood as the default stand-alone mode where the chip gets -the temperature and controls external devices via its Tout pin or -tells other i2c's about it if they care. The other mode is called -"1SHOT", that means that it only figures out about the temperature -when it is explicitly told to do so; this can be seen as power saving -mode. - -Now if you want to read REG_COUNT and REG_SLOPE, you have to either -stop the continuous conversions until the contents of these registers -are valid, or, in 1SHOT mode, you have to have one conversion made. - - - -Accessing DS1621 via /proc interface (part II and end) ------------------------------------------------------- - -The continuous file is rw. Reading gives "1" when the chip is in -continuous mode and "0" for 1SHOT. - Writing accepts "1" to put it -into continuous mode or "0" for 1SHOT. - -The enable file is rw. Reading gives "1" if in continuous mode the -DS1621 is "running" or if in 1SHOT mode it is "shooting". In fact, the -value returned here is the negated DONE bit, just like a "BUSY" -flag. This means, that the "1" tells you that the values in REG_COUNT -and REG_SLOPE are not valid. "0", on the other hand, means that the -continuous conversion had been stopped long enough to provide valid -readings and that one shot has successfully been fi- red, -respectively. - Writing accepts "1" to start continuous conversion or -to pull the trigger in 1SHOT mode, and "0" stops continuous conversion -to allow for valid readings. Writing "0" in 1SHOT doesn't make much -sense since you cannot catch a bullet, can you? No, the thing is that -DS1621 does only do one conversion then anyway, and after that, -there's nothing to stop. - -Last, but best try writing "0" to the "continuous" file and after that -"1" to the "enable" file. This gives you the precise temperature with -two digits after the radix (decimal point). -The precise results are only updated if the DONE bit was set, thus you -have to stop continuous conversion early enough prior to reading, -i. e. 1000ms. And, on the other hand, you shouldn't forget to fire off -1SHOT in order to get the actual temperature rather than that of the -day before yesterday. So read enable before any of these. - - -Chip Features -------------- - -Chip `ds1621' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - alarms NONE NONE R 0 - enable NONE NONE RW 0 - continuous NONE NONE RW 0 - polarity NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - temp SENSORS_DS1621_TEMP temp:3 - temp_hyst SENSORS_DS1621_TEMP_HYST temp:2 - temp_over SENSORS_DS1621_TEMP_OVER temp:1 - alarms SENSORS_DS1621_ALARMS alarms:1 - enable SENSORS_DS1621_ENABLE enable:1 - continuous SENSORS_DS1621_CONTINUOUS continuous:1 - polarity SENSORS_DS1621_POLARITY polarity:1 diff --git a/doc/chips/eeprom b/doc/chips/eeprom deleted file mode 100644 index 7d14c711..00000000 --- a/doc/chips/eeprom +++ /dev/null @@ -1,228 +0,0 @@ -Kernel driver `eeprom.o' -======================== - -Status: Complete and well-tested - -Supported chips: - * Any EEPROM chip in the designated address range - Prefix: 'eeprom' - Addresses scanned: I2C 0x50 - 0x57 - Datasheets: Publicly available from: - Atmel (www.atmel.com), - Catalyst (www.catsemi.com), - Fairchild (www.fairchildsemi.com), - Microchip (www.microchip.com), - Philips (www.semiconductor.philips.com), - Rohm (www.rohm.com), - ST (www.st.com), - Xicor (www.xicor.com), - and others. - - Chip Size (bits) Address - 24C01 1K 0x50 (shadows at 0x51 - 0x57) - 24C01A 1K 0x50 - 0x57 (Typical device on DIMMs) - 24C02 2K 0x50 - 0x57 - 24C04 4K 0x50, 0x52, 0x54, 0x56 - (additional data at 0x51, 0x53, 0x55, 0x57) - 24C08 8K 0x50, 0x54 (additional data at 0x51, 0x52, - 0x53, 0x55, 0x56, 0x57) - 24C16 16K 0x50 (additional data at 0x51 - 0x57) - Sony 2K 0x57 - - Atmel 34C02B 2K 0x50 - 0x57, SW write protect at 0x30-37 - Catalyst 34FC02 2K 0x50 - 0x57, SW write protect at 0x30-37 - Catalyst 34RC02 2K 0x50 - 0x57, SW write protect at 0x30-37 - Fairchild 34W02 2K 0x50 - 0x57, SW write protect at 0x30-37 - Microchip 24AA52 2K 0x50 - 0x57, SW write protect at 0x30-37 - ST M34C02 2K 0x50 - 0x57, SW write protect at 0x30-37 - - -Author: Frodo Looijaard and Philip Edelbrock - - - -Module Parameters ------------------ - -* checksum: int - Only accept eeproms whose checksum is correct -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_eeprom: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `eeprom' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This is a simple EEPROM module meant to enable reading the first 256 bytes -of an EEPROM (on a SDRAM DIMM for example). However, it will access serial -EEPROMs on any I2C adapter. The supported devices are generically -called 24Cxx, and are listed above; however the numbering -for these industry-standard devices may vary by manufacturer. - -This module was a programming exercise to get used to the new project -organization laid out by Frodo, but it should be at least completely -effective for decoding the contents of EEPROMs on DIMMs. - -DIMMS will typically contain a 24C01A or 24C02, or the 34C02 variants. -The other devices will not be found on a DIMM because -they respond to more than one address. - -DDC Monitors may contain any device. Often a 24C01, which responds -to all 8 addresses, is found. See the 'ddcmon' driver which has -specialized /proc entries for DDC monitors. If the eeprom driver is -loaded before the ddcmon driver and there is no 'ignore' line in the -/etc/sensors.conf file, the eeprom driver will latch onto the DDC monitor -eeprom. - -Recent Sony Vaio laptops have an EEPROM at 0x57. We couldn't get the -specification, so it is guess work and far from being complete. - -The Microchip 24AA52/24LCS52, ST M34C02, and others support an additional -software write protect register at 0x30 - 0x37 (0x20 less than the -memory location). The chip responds to "write quick" detection at this -address but does not respond to byte reads. -If this register is present, the lower 128 bytes of the memory -array are not write protected. Any byte data write to this address -will write protect the memory array permanently, and the device -will no longer respond at the 0x30-37 address. -The eeprom driver does not support this register. - -Lacking functionality: - -* Full support for larger devices (24C04, 24C08, 24C16). These are -not typically found on a PC. These devices will appear as separate -devices at multiple addresses. - -* Support for really large devices (24C32, 24C64, 24C128, 24C256, 24C512). -These devices require two-byte address fields and are not supported. - -* Enable Writing. Again, no technical reason why not, but making it easy -to change the contents of the EEPROMs (on DIMMs anyway) also makes it easy -to disable the DIMMs (potentially preventing the computer from booting) -until the values are restored somehow. - - -Use: - -After inserting the module (and any other required smbus/i2c modules), you -should have some EEPROM directories in /proc/sys/dev/sensors/ of names such -as "eeprom-i2c-0-50". Inside each of these is a series of files which -represent 16 bytes blocks from the EEPROM. The data is in decimal (base -10) delimited by spaces. - -Note: - -EEPROMs reported are not nessesarily all from DIMMs. Xeon processors, for -example, have serial EEPROMs in them connected to the SMBus which will be -found by the module. Take care to ignore the output of decode-dimms.pl for -these EEPROMs. There is decode-xeon.pl for them. Same applies to Vaio -EEPROMs, which have decode-vaio.pl. - -The driver caches the data from the monitor and only rereads it -from the eeprom if the cache is more than 5 minutes old. - - -Decode-dimms.pl ---------------- - -This Perl script attempts to make sense of the first 128 bytes of a SDRAM -PC-100 DIMM. Using the 'Serial Presence Detect (SPD)' Spec (Rev1.2a)** from -Intel. When finished, it will decode and report all the values defined in -the spec. Much of the information is technical timing and interfacing info -(probably not all used by the BIOS or clocking IC). - -Note: During testing, we noticed that many DIMMs have trucated SPD records. -I'm not sure if these conform to an old spec, or if the manufacturers are -simply just taking shortcuts. But, many DIMMs have all zeros stored past -byte 21. I asked an Intel SDRAM tester, Sat Kolli (skolli@smartm.com), -about this and this is what he had to say: - -"[...] Now in terms of SPD contents, you are right that people do all kinds -of things. The way to insure that any module works is to look for the most -basic information, such as module bank density, number of banks, and device -addresses. That will give you the module size and what devices are used. It -is very difficult to verify if the module is PC-100, because of -inconsistencies between spd data from different manufacturers. You could -read the timing information or the special Intel bytes (126 & 127) but I do -not know how many program that information. These inconsistencies may be -minimized if you or your customers stay with some of the better known -manufacturers." (Thanks goes to Sat Kolli for his comments and help.) - -Use: - -After inserting the necessary modules, run the script! - -Notes: - -The script assumes that Perl can be found at /usr/bin/perl. If different, -you will need to adjust the first line of the file accordingly, or else -you will get a strange "decode-dimms.pl: no such file or directory" error. - -Also note that the script assumes that _all_ the eeproms belong to DIMMs, -which may not be the case. - - -Decode-vaio.pl --------------- - -This Perl script looks for a Sony Vaio EEPROM at 0x57. If your system is not -a Sony Vaio laptop, you just don't care. If your system is an old Vaio, you -probably don't have an EEPROM on it and this script will be useless to you -as well. - -Use: - -After inserting the necessary modules, run the script! - -Notes: - -The script assumes that Perl can be found at /usr/bin/perl. If different, -you will need to adjust the first line of the file accordingly, or else -you will get a strange "decode-vaio.pl: no such file or directory" error. - - -Decode-edid.pl - -This Perl script acts as an interface between the eeprom module and -parse-edid, which is part of read-edid. Read-edid is a tool for gathering -information on VESA PNP monitors. It is somewhat similar to what our -ddcmon driver does, except that ddcmon outputs user-oriented data while -read-edid generates a a computer oriented configuration file (primarily -for XFree86). - -Read-edid is made of two components, get-edid which retrieves binary data -from the monitor, and parse-edid which decodes the data into useful -information. Get-edid uses low level functions, and relies on compliance -of both the video card and the monitor to some standard (DCC as it is -called). It may not work for everyone. On the other hand, some video -cards make this information available on an I2C bus and we are able to -get it using our eeprom module. That's why we wrote this script that -converts the data as exported by our eeprom module into what parse-edid -expects from get-edid. That way, users who can't get get-edid to work -still have a chance to be able to retrieve the wanted information thanks -to the lm_sensors modules and tools. - -Use: - -Unload the ddcmon if it was loaded, load the eeprom module instead. Then, -run the script. The script will try to figure out on which I2C bus and at -which address is the eeprom, but it may fail. In this case, you can pass -the parameters to the script. Examples: - - decode-edid.pl 1 - decode-edid.pl 2 0x50 - -You will find additional details in the script itself. Read-edid is avilable -there: - http://john.fremlin.de/programs/linux/read-edid/ diff --git a/doc/chips/f71805f b/doc/chips/f71805f deleted file mode 100644 index 40ee929a..00000000 --- a/doc/chips/f71805f +++ /dev/null @@ -1,107 +0,0 @@ -Kernel driver `f71805f.o' -========================= - -Status: Beta. - -Supported chips: - * Fintek F71805F/FG - Addresses scanned: none, address read from Super I/O config space - Prefix: 'f71805f' - Datasheet: Provided by Fintek on request - -Author: Jean Delvare - -Thanks to Denis Kieft from Barracuda Networks for the donation of a -test system (custom Jetway K8M8MS motherboard, with CPU and RAM) and -for providing initial documentation. - -Thanks to Kris Chen from Fintek for answering technical questions and -providing additional documentation. - -Thanks to Chris Lin from Jetway for providing wiring schematics and -answering technical questions. - - -Description ------------ - -The Fintek F71805F/FG Super I/O chip includes complete hardware monitoring -capabilities. It can monitor up to 9 voltages (counting its own power -source), 3 fans and 3 temperature sensors. - -This chip also has fan controlling features, using either DC or PWM, in -three different modes (one manual, two automatic). The driver doesn't -support these features yet. - -The driver assumes that no more than one chip is present, which seems -reasonable. - - -Voltage Monitoring ------------------- - -Voltages are sampled by an 8-bit ADC with a LSB of 8 mV. The supported -range is thus from 0 to 2.040 V. Voltage values outside of this range -need external resistors. An exception is in0, which is used to monitor -the chip's own power source (+3.3V), and is divided internally by a -factor 2. - -The two LSB of the voltage limit registers are not used (always 0), so -you can only set the limits in steps of 32 mV (before scaling). - -The wirings and resistor values suggested by Fintek are as follow: - - pin expected - name use R1 R2 divider raw val. - -in0 VCC VCC3.3V int. int. 2.00 1.65 V -in1 VIN1 VTT1.2V 10K - 1.00 1.20 V -in2 VIN2 VRAM 100K 100K 2.00 ~1.25 V (1) -in3 VIN3 VCHIPSET 47K 100K 1.47 2.24 V (2) -in4 VIN4 VCC5V 200K 47K 5.25 0.95 V -in5 VIN5 +12V 200K 20K 11.00 1.05 V -in6 VIN6 VCC1.5V 10K - 1.00 1.50 V -in7 VIN7 VCORE 10K - 1.00 ~1.40 V (1) -in8 VIN8 VSB5V 200K 47K 1.00 0.95 V - -(1) Depends on your hardware setup. -(2) Obviously not correct, swapping R1 and R2 would make more sense. - -These values can be used as hints at best, as motherboard manufacturers -are free to use a completely different setup. As a matter of fact, the -Jetway K8M8MS uses a significantly different setup. You will have to -find out documentation about your own motherboard, and edit sensors.conf -accordingly. - -Each voltage measured has associated low and high limits, each of which -triggers an alarm when crossed. - - -Fan Monitoring --------------- - -Fan rotation speeds are reported as 12-bit values from a gated clock -signal. Speeds down to 366 RPM can be measured. There is no theoretical -high limit, but values over 6000 RPM seem to cause problem. The effective -resolution is much lower than you would expect, the step between different -register values being 10 rather than 1. - -The chip assumes 2 pulse-per-revolution fans. - -An alarm is triggered if the rotation speed drops below a programmable -limit or is too low to be measured. - - -Temperature Monitoring ----------------------- - -Temperatures are reported in degrees Celsius. Each temperature measured -has a high limit, those crossing triggers an alarm. There is an associated -hysteresis value, below which the temperature has to drop before the -alarm is cleared. - -All temperature channels are external, there is no embedded temperature -sensor. Each channel can be used for connecting either a thermal diode -or a thermistor. The driver reports the currently selected mode, but -doesn't allow changing it. In theory, the BIOS should have configured -everything properly. diff --git a/doc/chips/fscher b/doc/chips/fscher deleted file mode 100644 index 2b8fee45..00000000 --- a/doc/chips/fscher +++ /dev/null @@ -1,266 +0,0 @@ -Kernel driver `fscher.o' -======================= - -Status: Stable - Tested with motherboard D1562 - - Think twice before you're using the write mode of some - variables, especially the watchdog - - -Supported chips: - * Fujitsu-Siemens Hermes chip - Prefix: 'fscher' - Addresses scanned: I2C 0x73 - -Author: Reinhard Nissl based on work from Hermann Jung - , Frodo Looijaard and Philip Edelbrock - - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_fscher: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `fscher' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -This driver implements support for the Fujitsu-Siemens Hermes chip. -It is described in the 'Register Set Specification BMC Hermes based -Systemboard' from Fujitsu-Siemens. - -The Hermes chip implements a hardware-based system management, -e.g. for controlling fan speed and core voltage. -There is also a watchdog counter on the chip which can trigger -an alarm and even shut the system down. - -The chip provides three temperature values (CPU, motherboard and auxiliary), -three voltage values (+12V, +5V and battery) and three fans (power supply, -CPU and auxiliary). - -Temperatures are measured in degrees Celsius. The resolution is 1 degree. - -Fan rotation speeds are reported in RPM (rotations per minute). -The value can be divided by a programmable divider (1, 2 or 4) which -is stored on the chip. - -Voltage sensors (also known as "in" sensors) report their values in volts. - -All values are reported as final values from the driver. -There is no need for further calculations. - - -Detailed description --------------------- - -Below you'll find a single line description of all the bit values. With this -information, you're able to decode e. g. alarms, wdog, etc. -To make use of the watchdog, you'll need to set the watchdog time and enable -the watchdog. After that it is necessary to restart the watchdog time within -the specified period of time, or a system reset will occur. - -* rev:1 - READING & 0xff = 0x??: HERMES revision identification - -* alarms:1 - READING & 0x80 = 0x80: CPU throttling active - READING & 0x80 = 0x00: CPU running at full speed - - READING & 0x10 = 0x10: software event (see control:1) - READING & 0x10 = 0x00: no software event - - READING & 0x08 = 0x08: watchdog event (see wdog:2) - READING & 0x08 = 0x00: no watchdog event - - READING & 0x02 = 0x02: thermal event (see temp*:1) - READING & 0x02 = 0x00: no thermal event - - READING & 0x01 = 0x01: fan event (see fan*:1) - READING & 0x01 = 0x00: no fan event - - READING & 0x13 ! 0x00: ALERT LED is flashing - -* control:1 - READING & 0x01 = 0x01: software event - READING & 0x01 = 0x00: no software event - - WRITING & 0x01 = 0x01: set software event - WRITING & 0x01 = 0x00: clear software event - -* wdog:3 - READING & 0x80 = 0x80: power off on watchdog event while thermal event - READING & 0x80 = 0x00: watchdog power off disabled (just system reset enabled) - - READING & 0x40 = 0x40: watchdog timebase 60 seconds (see also wdog:1) - READING & 0x40 = 0x00: watchdog timebase 2 seconds - - READING & 0x10 = 0x10: watchdog enabled - READING & 0x10 = 0x00: watchdog disabled - - WRITING & 0x80 = 0x80: enable "power off on watchdog event while thermal event" - WRITING & 0x80 = 0x00: disable "power off on watchdog event while thermal event" - - WRITING & 0x40 = 0x40: set watchdog timebase to 60 seconds - WRITING & 0x40 = 0x00: set watchdog timebase to 2 seconds - - WRITING & 0x20 = 0x20: disable watchdog - - WRITING & 0x10 = 0x10: enable watchdog / restart watchdog time - -* wdog:2 - READING & 0x02 = 0x02: watchdog system reset occurred - READING & 0x02 = 0x00: no watchdog system reset occurred - - WRITING & 0x02 = 0x02: clear watchdog event - -* wdog:1 - READING & 0xff = 0x??: configured watch dog time in units (see wdog:3 0x40) - - WRITING & 0xff = 0x??: configure watch dog time in units - -* in*:1 (0: +5V, 1: +12V, 2: onboard 3V battery) - READING: actual voltage value - -* temp*:1 (1: CPU sensor, 2: onboard sensor, 3: auxiliary sensor) - READING & 0x02 = 0x02: thermal event (overtemperature) - READING & 0x02 = 0x00: no thermal event - - READING & 0x01 = 0x01: sensor is working - READING & 0x01 = 0x00: sensor is faulty - - WRITING & 0x02 = 0x02: clear thermal event - -* temp*:2 (1: CPU sensor, 2: onboard sensor, 3: auxiliary sensor) - READING: actual temperature value - -* fan*:1 (1: power supply fan, 2: CPU fan, 3: auxiliary fan) - READING & 0x04 = 0x04: fan event (fan fault) - READING & 0x04 = 0x00: no fan event - - WRITING & 0x04 = 0x04: clear fan event - -* fan*:2 (1: power supply fan, 2: CPU fan, 3: auxiliary fan) - READING & 0x03 = 0x03: 8 ripples are one fan turn - READING & 0x03 = 0x02: 4 ripples are one fan turn - READING & 0x03 = 0x01: 2 ripples are one fan turn - - WRITING & 0x03 = 0x03: set prescaler to "8 ripples are one fan turn" - WRITING & 0x03 = 0x02: set prescaler to "4 ripples are one fan turn" - WRITING & 0x03 = 0x01: set prescaler to "2 ripples are one fan turn" - -* fan*:3 (1: power supply fan, 2: CPU fan, 3: auxiliary fan) - READING & 0xff = 0x00: fan may be switched off - READING & 0xff = 0x01: fan must run at least at minimum speed (supply: 6V) - READING & 0xff = 0xff: fan must run at maximum speed (supply: 12V) - READING & 0xff = 0x??: fan must run at least at given speed (supply: 6V..12V) - - WRITING & 0xff = 0x00: fan may be switched off - WRITING & 0xff = 0x01: fan must run at least at minimum speed (supply: 6V) - WRITING & 0xff = 0xff: fan must run at maximum speed (supply: 12V) - WRITING & 0xff = 0x??: fan must run at least at given speed (supply: 6V..12V) - -* fan*:4 (1: power supply fan, 2: CPU fan, 3: auxiliary fan) - READING: actual RPM value - - -Limitations ------------ - -* Measuring fan speed -It seems that the chip counts "ripples" (typical fans produce 2 ripples per -rotation while VERAX fans produce 18) in a 9-bit register. This register is -read out every second, then the ripple prescaler (2, 4 or 8) is applied and -the result is stored in the 8 bit output register. Due to the limitation of -the counting register to 9 bits, it is impossible to measure a VERAX fan -properly (even with a prescaler of 8). At its maximum speed of 3500 RPM the -fan produces 1080 ripples per second which causes the counting register to -overflow twice, leading to only 186 RPM. - -* Measuring input voltages -in2 ("battery") reports the voltage of the onboard lithium battery and not -+3.3V from the power supply. - -* Undocumented features -Fujitsu-Siemens Computers has not documented all features of the chip so far. -Their software, System Guard, shows that there are a still some features which -cannot be controled by this implementation. - - -Chip Features -------------- - -Chip 'fscher' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -rev - - R- 0 -alarms - - R- 0 -control - - RW 0 -in0 - - R- 2 -in1 - - R- 2 -in2 - - R- 2 -temp1 - - R- 0 -temp2 - - R- 0 -temp3 - - R- 0 -temp1_state temp1 temp1 RW 0 -temp2_state temp2 temp2 RW 0 -temp3_state temp3 temp3 RW 0 -fan1 - - R- 0 -fan2 - - R- 0 -fan3 - - R- 0 -fan1_min fan1 fan1 RW 0 -fan2_min fan2 fan2 RW 0 -fan3_min fan3 fan3 RW 0 -fan1_state fan1 fan1 RW 0 -fan2_state fan2 fan2 RW 0 -fan3_state fan3 fan3 RW 0 -fan1_ripple fan1 fan1 RW 0 -fan2_ripple fan2 fan2 RW 0 -fan3_ripple fan3 fan3 RW 0 -wdog_preset - - RW 0 -wdog_state wdog_preset wdog_preset RW 0 -wdog_control wdog_preset wdog_preset RW 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -rev SENSORS_FSCHER_REV rev:1 -alarms SENSORS_FSCHER_EVENT alarms:1 -control SENSORS_FSCHER_CONTROL control:1 -in0 SENSORS_FSCHER_VOLTAGE1 in0:1 -in1 SENSORS_FSCHER_VOLTAGE2 in1:1 -in2 SENSORS_FSCHER_VOLTAGE3 in2:1 -temp1 SENSORS_FSCHER_TEMP1 temp1:2 -temp2 SENSORS_FSCHER_TEMP2 temp2:2 -temp3 SENSORS_FSCHER_TEMP3 temp3:2 -temp1_state SENSORS_FSCHER_TEMP1_STATE temp1:1 -temp2_state SENSORS_FSCHER_TEMP2_STATE temp2:1 -temp3_state SENSORS_FSCHER_TEMP3_STATE temp3:1 -fan1 SENSORS_FSCHER_FAN1 fan1:4 -fan2 SENSORS_FSCHER_FAN2 fan2:4 -fan3 SENSORS_FSCHER_FAN3 fan3:4 -fan1_min SENSORS_FSCHER_FAN1_MIN fan1:2 -fan2_min SENSORS_FSCHER_FAN2_MIN fan2:2 -fan3_min SENSORS_FSCHER_FAN3_MIN fan3:2 -fan1_state SENSORS_FSCHER_FAN1_STATE fan1:1 -fan2_state SENSORS_FSCHER_FAN2_STATE fan2:1 -fan3_state SENSORS_FSCHER_FAN3_STATE fan3:1 -fan1_ripple SENSORS_FSCHER_FAN1_RIPPLE fan1:3 -fan2_ripple SENSORS_FSCHER_FAN2_RIPPLE fan2:3 -fan3_ripple SENSORS_FSCHER_FAN3_RIPPLE fan3:3 -wdog_preset SENSORS_FSCHER_WDOG_PRESET wdog:1 -wdog_state SENSORS_FSCHER_WDOG_STATE wdog:2 -wdog_control SENSORS_FSCHER_WDOG_CONTROL wdog:3 diff --git a/doc/chips/fscpos b/doc/chips/fscpos deleted file mode 100644 index 0707dc0d..00000000 --- a/doc/chips/fscpos +++ /dev/null @@ -1,122 +0,0 @@ -Kernel driver `fscpos.o' -====================== - -Status: Beta - Tested with motherboard d1107 - - Think twice before you're using the write mode of some - variables, especially the watchdog - - -Supported chips: - * Fujitsu Siemens Poseidon chip - Prefix: 'fscpos' - Addresses scanned: I2C 0x73 - -Author: Hermann Jung - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This driver implements support for the Fujitsu Siemens Poseidon chip. -It is descibed in the 'Register Set Specification BMC Poseidon based -Systemboard' from Fujitsu Siemens. - -The poseidon chip implements a hardware based system management, -e.g. for controlling fan speed and core voltage. -There is also a watchdog counter on the chip which can trigger -an alarm and even shutdown the system. - -The chip provides three temperature values (cpu, motherboard and auxiliary), -three current values (12 volt, 5 volt and battery) and -three fans (power supply, cpu and auxiliary). - -Temperatures are measured in degrees Celsius. The resolution is 1 degree. - -Fan rotation speeds are reported in RPM (rotations per minute). -The value can be divided by a programmable divider (1, 2, 4 or 8) which -is stored on the chip. - -Voltage sensors (also known as IN sensors) report their values in volts. - -All values are reported as final values from the driver. -There is no need for further calculations. - -Chip Features -------------- - -Chip `fscpos' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - rev NONE NONE R 0 - event NONE NONE R 0 - control NONE NONE RW 0 - volt12 NONE NONE R 2 - volt5 NONE NONE R 2 - voltbatt NONE NONE R 2 - temp1 NONE NONE R 0 - temp2 NONE NONE R 0 - temp3 NONE NONE R 0 - temp1_state temp1 temp1 RW 0 - temp2_state temp2 temp2 RW 0 - temp3_state temp3 temp3 RW 0 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - fan1_state fan1 fan1 RW 0 - fan2_state fan2 fan2 RW 0 - fan3_state fan3 fan3 RW 0 - fan1_ripple fan1 fan1 RW 0 - fan2_ripple fan2 fan2 RW 0 - fan3_ripple fan3 fan3 RW 0 - wdog_preset NONE NONE RW 0 - wdog_state wdog_preset wdog_preset RW 0 - wdog_control wdog_preset wdog_preset RW 0 - - - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - rev FSCPOS_SYSCTL_REV rev:1 - event FSCPOS_SYSCTL_EVENT event:1 - control FSCPOS_SYSCTL_CONTROL control:1 - volt12 FSCPOS_SYSCTL_VOLTAGE1 volt0:1 - volt5 FSCPOS_SYSCTL_VOLTAGE2 volt1:1 - voltbatt FSCPOS_SYSCTL_VOLTAGE3 volt2:1 - temp1 FSCPOS_SYSCTL_TEMP1 temp0:2 - temp2 FSCPOS_SYSCTL_TEMP2 temp1:2 - temp3 FSCPOS_SYSCTL_TEMP3 temp2:2 - temp1_state FSCPOS_SYSCTL_TEMP1_STATE temp0:1 - temp2_state FSCPOS_SYSCTL_TEMP2_STATE temp1:1 - temp3_state FSCPOS_SYSCTL_TEMP3_STATE temp2:1 - fan1 FSCPOS_SYSCTL_FAN1 fan0:4 - fan2 FSCPOS_SYSCTL_FAN2 fan1:4 - fan3 FSCPOS_SYSCTL_FAN3 fan2:4 - fan1_min FSCPOS_SYSCTL_FAN1_MIN fan0:2 - fan2_min FSCPOS_SYSCTL_FAN2_MIN fan1:2 - fan1_state FSCPOS_SYSCTL_FAN1_STATE fan0:1 - fan2_state FSCPOS_SYSCTL_FAN2_STATE fan1:1 - fan3_state FSCPOS_SYSCTL_FAN3_STATE fan2:1 - fan1_ripple FSCPOS_SYSCTL_FAN1_RIPPLE fan0:3 - fan2_ripple FSCPOS_SYSCTL_FAN2_RIPPLE fan1:3 - fan3_ripple FSCPOS_SYSCTL_FAN3_RIPPLE fan2:3 - wdog_preset FSCPOS_SYSCTL_WDOG_PRESET wdog:1 - wdog_state FSCPOS_SYSCTL_WDOG_STATE wdog:2 - wdog_control FSCPOS_SYSCTL_WDOG_CONTROL wdog:3 - diff --git a/doc/chips/fscscy b/doc/chips/fscscy deleted file mode 100644 index 6cc2f2ee..00000000 --- a/doc/chips/fscscy +++ /dev/null @@ -1,251 +0,0 @@ -Kernel driver `fscscy.o' -====================== - -Status: Beta - Tested with motherboard D1230 - Should also work with D1204, D1306 and D1307 - - Think twice before you're using the write mode of some - variables, especially the watchdog (Not my comment, but it makes - good sense to observe :-) - - -Supported chips: - * Fujitsu Siemens Scylla chip - Prefix: 'fscscy' - Addresses scanned: I2C 0x73 - -Author: Martin Knoblauch - -Acknowledgement: - This code has been greatly inspired by Hermann Jung - and his work on the Poseidon driver (fscpos) - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This driver implements support for the Fujitsu Siemens Scylla chip. -The code is based on the "fscpos" driver for the FSC Poseidon chip. -In fact, it seems the Scylla is a superset of the "Poseidon", "Poseidon II" -and "Hydra" chips. - -The register readings/setting have been deduced from the 'Register Set -Specification BMC Poseidon based Systemboard' by Fujitsu Siemens and the -"sbbmon.ini" file from the Fujitsu-Siemens ServerView software. - -The scylla chip implements a hardware based system management, -e.g. for controlling fan speed and core voltage. -There is also a watchdog counter on the chip which can trigger -an alarm and even shutdown the system. See above for more details about using -the watchdog feature. - -The chip provides four temperature values (cpu0/1, motherboard and auxiliary), -three current values (12 volt, 5 volt and battery) and up to -six fans (power supply, cpu and auxiliary). - -Temperatures are measured in degrees Celsius. The resolution is 1 degree. -In addition to state and actual temperature, the temperature sensors also export -a LIMIT temperature for each sensor. The meaning of the information itself is -obvious. The rest is guesswork. It likely triggers an alarm/event as soon as it is -reached. The authors feeling is that it is even a writeable register. But beeing of -the cautios kind he did not implement writing the LIMIT resister. The driver itself -keeps track of the minimum and maximum temperatures since module load. The more often -the module is accessed, the more meaningful these values are. - -Fan rotation speeds are reported in RPM (rotations per minute). -The value can be divided by a programmable divider (1, 2, 4 or 8) which -is stored on the chip. - -Voltage sensors (also known as IN sensors) report their values in volts. - -All values are reported as final values from the driver. -There is no need for further calculations. - - -Using The Watchdog ------------------- - -This part was mostly contributed by A'rpi . Thanks! -I (Jean Delvare) edited the text for greater clarity, mainly to integrate -the e-mail exchange I and A'rpi had as a sequel of the original report. -Here it goes. - -I've spent few hours experiencing with the watchdog feature of the Fujitsu -Siemens server board (don't ask the model name, what I know is that it uses -Serverworks CSB5 chipset) using lm_sensors' fscscy driver. - -OK, so there is /proc/sys/dev/sensors/fscscy-i2c-0-73/wdog, containing 3 -8-bit values for the 3 watchdog registers. - -The first one is the time counter, it counts backwards. It's in 2 seconds -base, so writting 30 there means 60 seconds delay. It seems the whole range -(0 to 255) is supported, so up to 510 seconds (8.5 minutes). Writting 0 means -immediate hardware reset. The value you can read back is the same as you wrote -there, not the current value of the counter (as I expected). - -The second number is supposed to be a state register. It doesn't matter what -value I put there. It's always 0. Even if I write a non-zero value there, i got -0 back. Maybe it's non-zero at the moment of reset :) - -The third is the control register, with 5th (value 16), 6th (value 32) and 8th -(value 128) bits used only. If I write 16 or 144 (128+16), it means system -reset when the counter reaches 0. If I add 32 (for a value of 48 or 176), no -reset will occur. - -So, the world's simplest watchdog using this mainboard: - -while true ; do - echo 30 0 16 > /proc/sys/dev/sensors/fscscy-i2c-0-73/wdog - sleep 10 -done - -It does hardware reset after 1 minute, if this script is killed or system -hang-up occurs. Adjust the 30 and 10 values according to you needs, but -remember you must sleep less than the reset countdown time (here, 30*2-10 -gives us a 50 seconds margin, which is more than enough). - -Also note that BIOS has a strange setting, named 'OS Boot Retry Count', set -to 0 by default, it changes watchdog behaviour to power off instead of reset. -(0=poweroff 1..7=reset). It took me a while to find this. This behavior is -probably related to the "Reset Limit" parameter defined by the ACPI -specification (3.3.24 System Reset (Type 23)). It sets how many unintentional -resets can be performed in a row before giving up (and shut down). - -Please add the above to the documentation (doc/chips/fscscy), so i can save -a few hours of resetting for other people :) - - -Chip Features -------------- - -Chip `fscscy' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - rev NONE NONE R 0 - event NONE NONE R 0 - control NONE NONE RW 0 - volt12 NONE NONE R 2 - volt5 NONE NONE R 2 - voltbatt NONE NONE R 2 - temp1 NONE NONE R 0 - temp2 NONE NONE R 0 - temp3 NONE NONE R 0 - temp4 NONE NONE R 0 - temp1_state temp1 temp1 RW 0 - temp2_state temp2 temp2 RW 0 - temp3_state temp3 temp3 RW 0 - temp4_state temp4 temp4 RW 0 - temp1_lim temp1 temp1 R* 0 - temp2_lim temp2 temp2 R* 0 - temp3_lim temp3 temp3 R* 0 - temp4_lim temp4 temp4 R* 0 - temp1_min temp1 temp1 R 0 - temp2_min temp2 temp2 R 0 - temp3_min temp3 temp3 R 0 - temp4_min temp4 temp4 R 0 - temp1_max temp1 temp1 R 0 - temp2_max temp2 temp2 R 0 - temp3_max temp3 temp3 R 0 - temp4_max temp4 temp4 R 0 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan4 NONE NONE R 0 - fan5 NONE NONE R 0 - fan6 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - fan3_min fan3 fan3 RW 0 - fan4_min fan4 fan4 RW 0 - fan5_min fan5 fan5 RW 0 - fan6_min fan6 fan6 RW 0 - fan1_state fan1 fan1 RW 0 - fan2_state fan2 fan2 RW 0 - fan3_state fan3 fan3 RW 0 - fan4_state fan4 fan4 RW 0 - fan5_state fan5 fan5 RW 0 - fan6_state fan6 fan6 RW 0 - fan1_ripple fan1 fan1 RW 0 - fan2_ripple fan2 fan2 RW 0 - fan3_ripple fan3 fan3 RW 0 - fan4_ripple fan4 fan4 RW 0 - fan5_ripple fan5 fan5 RW 0 - fan6_ripple fan6 fan6 RW 0 - wdog_preset NONE NONE RW 0 - wdog_state wdog_preset wdog_preset RW 0 - wdog_control wdog_preset wdog_preset RW 0 - - R*: Maybe writable, but due to lack of documentation the author did not dare - to implement it :-) - - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - rev FSCSCY_SYSCTL_REV rev:1 - event FSCSCY_SYSCTL_EVENT event:1 - control FSCSCY_SYSCTL_CONTROL control:1 - volt12 FSCSCY_SYSCTL_VOLTAGE1 volt0:1 - volt5 FSCSCY_SYSCTL_VOLTAGE2 volt1:1 - voltbatt FSCSCY_SYSCTL_VOLTAGE3 volt2:1 - temp1 FSCSCY_SYSCTL_TEMP1 temp0:2 - temp2 FSCSCY_SYSCTL_TEMP2 temp1:2 - temp3 FSCSCY_SYSCTL_TEMP3 temp2:2 - temp4 FSCSCY_SYSCTL_TEMP4 temp3:2 - temp1_state FSCSCY_SYSCTL_TEMP1_STATE temp0:1 - temp2_state FSCSCY_SYSCTL_TEMP2_STATE temp1:1 - temp3_state FSCSCY_SYSCTL_TEMP3_STATE temp2:1 - temp4_state FSCSCY_SYSCTL_TEMP4_STATE temp3:1 - temp1_lim FSCSCY_SYSCTL_TEMP1_LIM temp0:3 - temp2_lim FSCSCY_SYSCTL_TEMP2_LIM temp1:3 - temp3_lim FSCSCY_SYSCTL_TEMP3_LIM temp2:3 - temp4_lim FSCSCY_SYSCTL_TEMP4_LIM temp3:3 - temp1_min FSCSCY_SYSCTL_TEMP1_MIN temp0:4 - temp2_min FSCSCY_SYSCTL_TEMP2_MIN temp1:4 - temp3_min FSCSCY_SYSCTL_TEMP3_MIN temp2:4 - temp4_min FSCSCY_SYSCTL_TEMP4_MIN temp3:4 - temp1_max FSCSCY_SYSCTL_TEMP1_MIN temp0:5 - temp2_max FSCSCY_SYSCTL_TEMP2_MIN temp1:5 - temp3_max FSCSCY_SYSCTL_TEMP3_MIN temp2:5 - temp4_max FSCSCY_SYSCTL_TEMP4_MIN temp3:5 - fan1 FSCSCY_SYSCTL_FAN1 fan0:4 - fan2 FSCSCY_SYSCTL_FAN2 fan1:4 - fan3 FSCSCY_SYSCTL_FAN3 fan2:4 - fan4 FSCSCY_SYSCTL_FAN4 fan3:4 - fan5 FSCSCY_SYSCTL_FAN5 fan4:4 - fan6 FSCSCY_SYSCTL_FAN6 fan5:4 - fan1_min FSCSCY_SYSCTL_FAN1_MIN fan0:2 - fan2_min FSCSCY_SYSCTL_FAN2_MIN fan1:2 - fan3_min FSCSCY_SYSCTL_FAN3_MIN fan2:2 - fan4_min FSCSCY_SYSCTL_FAN4_MIN fan3:2 - fan5_min FSCSCY_SYSCTL_FAN5_MIN fan4:2 - fan6_min FSCSCY_SYSCTL_FAN6_MIN fan5:2 - fan1_state FSCSCY_SYSCTL_FAN1_STATE fan0:1 - fan2_state FSCSCY_SYSCTL_FAN2_STATE fan1:1 - fan3_state FSCSCY_SYSCTL_FAN3_STATE fan2:1 - fan4_state FSCSCY_SYSCTL_FAN4_STATE fan3:1 - fan5_state FSCSCY_SYSCTL_FAN5_STATE fan4:1 - fan6_state FSCSCY_SYSCTL_FAN6_STATE fan5:1 - fan1_ripple FSCSCY_SYSCTL_FAN1_RIPPLE fan0:3 - fan2_ripple FSCSCY_SYSCTL_FAN2_RIPPLE fan1:3 - fan3_ripple FSCSCY_SYSCTL_FAN3_RIPPLE fan2:3 - fan4_ripple FSCSCY_SYSCTL_FAN3_RIPPLE fan3:3 - fan5_ripple FSCSCY_SYSCTL_FAN3_RIPPLE fan4:3 - fan6_ripple FSCSCY_SYSCTL_FAN3_RIPPLE fan5:3 - wdog_preset FSCSCY_SYSCTL_WDOG_PRESET wdog:1 - wdog_state FSCSCY_SYSCTL_WDOG_STATE wdog:2 - wdog_control FSCSCY_SYSCTL_WDOG_CONTROL wdog:3 - diff --git a/doc/chips/gl518sm b/doc/chips/gl518sm deleted file mode 100644 index 02aaa6e5..00000000 --- a/doc/chips/gl518sm +++ /dev/null @@ -1,184 +0,0 @@ -Kernel driver `gl518sm.o' -========================= - -Status: Complete and well-tested - -Supported chips: - * Genesys Logic GL518SM release 0x00 - Prefix: 'gl518sm' - Addresses scanned: I2C 0x2c and 0x2d - Datasheet: http://www.genesyslogic.com/pdf - * Genesys Logic GL518SM release 0x80 - Prefix: 'gl518sm' - Addresses scanned: I2C 0x2c and 0x2d - Datasheet: http://www.genesyslogic.com/pdf - -Author: Frodo Looijaard , - Kyösti Mälkki - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_gl518sm_r00: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `gl518sm_r00' chip -* force_gl518sm_r80: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `gl518sm_r80' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - -Description ------------ - -IMPORTANT: For the revision 0x00 chip, the - in0, in1, and in2 values (+5, +3, and +12) CANNOT be read - unless you use the slow 'iterate' method. Limits will still - work even when iterate=0. See below. This is a limitation - of the chip, not the driver. - Note that the 'iterate' method was trimmed while porting the - driver to Linux 2.6 as we considered it too ugly for the thin - benefit. - - -This driver supports the Genesys Logic GL518SM chip. There are at least -two revision of this chip, which we call revision 0x00 and 0x80. Revision -0x80 chips support the reading of voltages directly, 0x00 only for VIN3. - -The GL518SM implements one temperature sensor, two fan rotation speed -sensors, and four voltage sensors. It can report alarms through the -computer speakers. - -Temperatures are measured in degrees Celsius. An alarm goes off while the -temperature is above the over temperature limit, and has not yet dropped -below the hysteresis limit. The alarm always reflects the current situation. -Measurements are guaranteed between -10 degrees and +110 degrees, with -a resolution of +-3 degrees. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. -In case when you have selected to turn Fan1 off, no Fan1 alarm is triggered. - -Fan readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 1900 RPM. - -Voltage sensors (also known as VIN sensors) report their values in volts. An -alarm is triggered if the voltage has crossed a programmable minimum or -maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. The VDD input -measures voltages between 0.000 and 5.865 volt, with a resolution of 0.023 -volt. The other inputs measure voltages between 0.000 and 4.845 volt, with a -resolution of 0.019 volt. Note that revision 0x00 chips do not support -reading the current voltage of any input except for VIN3; limit setting and -alarms work fine, though. There is code to compute them by iterating. - -When an alarm goes off, you can be warned by a beeping signal through -your computer speaker. It is possible to enable all beeping globally, -or only the beeping for some alarms. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once (except for temperature alarms). This means that the -cause for the alarm may already have disappeared! Note that in the current -implementation, all hardware registers are read whenever any data is read -(unless it is less than 1.5 seconds since the last update). This means that -you can easily miss once-only alarms. - -The GL518SM only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. - -Iteration Code --------------- - -IMPORTANT: For the revision 0x00 chip only, -you may select between three modes to read the vin0-2 inputs with -the following lines in /etc/sensors.conf: - - set iterate 0 Don't read in0-in2 inputs. - set iterate 1 Run the iteration loop, this takes up to 10 seconds. - set iterate 2 Show the results of the last iteration loop, - and start a new loop to run in the background. - -You may also set the iteration type with -'echo n > /proc/sys/dev/sensors/gl518sm-i2c-x-y/iterate'. - -If you have a rev 0x80 chip, the in0-in2 inputs are readable. -In this case, 'iterate' will be read-only and the read value is 3. - -This does NOT apply to the Linux 2.6 kernel driver, where the 'iteration' -code was dropped for being too ugly. - - -Chip Features -------------- - -Chip `gl518sm' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - vdd NONE NONE R 2 - vin1 NONE NONE R 2 - vin2 NONE NONE R 2 - vin3 NONE NONE R 2 - vdd_min vdd vdd RW 2 - vin1_min vin1 vin1 RW 2 - vin2_min vin2 vin2 RW 2 - vin3_min vin3 vin3 RW 2 - vdd_max vdd vdd RW 2 - vin1_max vin1 vin1 RW 2 - vin2_max vin2 vin2 RW 2 - vin3_max vin3 vin3 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - alarms NONE NONE R 0 - beep_enable alarms NONE RW 0 - beeps alarms alarms RW 0 - fan1_off NONE NONE RW 0 - fan1_off_pin NONE NONE RW 0 - iterate NONE NONE RW 0 - - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - vdd SENSORS_GL518_VDD vdd:3 - vin1 SENSORS_GL518_VIN1 vin1:3 - vin2 SENSORS_GL518_VIN2 vin2:3 - vin3 SENSORS_GL518_VIN3 vin3:3 - vdd_min SENSORS_GL518_VDD_MIN vdd:1 - vin1_min SENSORS_GL518_VIN1_MIN vin1:1 - vin2_min SENSORS_GL518_VIN2_MIN vin2:1 - vin3_min SENSORS_GL518_VIN3_MIN vin3:1 - vdd_max SENSORS_GL518_VDD_MAX vdd:2 - vin1_max SENSORS_GL518_VIN1_MAX vin1:2 - vin2_max SENSORS_GL518_VIN2_MAX vin2:2 - vin3_max SENSORS_GL518_VIN3_MAX vin3:2 - fan1 SENSORS_GL518_FAN1 fan1:2 - fan2 SENSORS_GL518_FAN2 fan2:2 - fan1_min SENSORS_GL518_FAN1_MIN fan1:1 - fan2_min SENSORS_GL518_FAN2_MIN fan2:1 - temp SENSORS_GL518_TEMP temp:3 - temp_hyst SENSORS_GL518_TEMP_HYST temp:2 - temp_over SENSORS_GL518_TEMP_OVER temp:1 - fan1_div SENSORS_GL518_FAN1_DIV fan_div:1 - fan2_div SENSORS_GL518_FAN2_DIV fan_div:2 - alarms SENSORS_GL518_ALARMS alarms:1 - beep_enable SENSORS_GL518_BEEP_ENABLE beep:1 - beeps SENSORS_GL518_BEEPS beep:2 - fan1_off SENSORS_GL518_FAN1OFF fan1off:1 - fan1_off_pin SENSORS_GL518_FAN1PIN fan1off:2 - iterate SENSORS_GL518_ITERATE iterate:1 - diff --git a/doc/chips/gl520sm b/doc/chips/gl520sm deleted file mode 100644 index 17d7c84a..00000000 --- a/doc/chips/gl520sm +++ /dev/null @@ -1,146 +0,0 @@ -Kernel driver `gl520sm.o' -========================= - -Status: Complete but experimental - -Supported chips: - * Genesys Logic GL520SM release 0x00 - Prefix: 'gl520sm' - Addresses scanned: I2C 0x2c and 0x2d - Datasheet: Not openly available - -Author: Frodo Looijaard , - Kyösti Mälkki - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - -Description ------------ - -This driver supports the Genesys Logic GL520SM chip. - -The GL520SM implements one temperature sensor, two fan rotation speed -sensors, four voltage sensors and the cpu VID lines. In addition, one input -can be configured as either a temperature or voltage sensor. -The sensor can report alarms through the computer speakers. - -Temperatures are measured in degrees Celsius. An alarm goes off while the -temperature is above the over temperature limit, and has not yet dropped -below the hysteresis limit. The alarm always reflects the current situation. -Measurements are guaranteed between 0 degrees and +110 degrees, with -a resolution of +-3 degrees. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. -In case when you have selected to turn Fan1 off, no Fan1 alarm is triggered -if measured temperature is below 'over temperature' limit. - -Fan readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 1900 RPM. - -Voltage sensors (also known as VIN sensors) report their values in volts. An -alarm is triggered if the voltage has crossed a programmable minimum or -maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. The VDD input -measures voltages between 0.000 and 5.865 volt, with a resolution of 0.023 -volt. The other inputs measure voltages between 0.000 and 4.845 volt, with a -resolution of 0.019 volt. - -When an alarm goes off, you can be warned by a beeping signal through -your computer speaker. It is possible to enable all beeping globally, -or only the beeping for some alarms. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once (except for temperature alarms). This means that the -cause for the alarm may already have disappeared! Note that in the current -implementation, all hardware registers are read whenever any data is read -(unless it is less than 1.5 seconds since the last update). This means that -you can easily miss once-only alarms. - -The GL520SM only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. - -Chip Features -------------- - -Chip `gl520sm' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - vdd NONE NONE R 2 - vin1 NONE NONE R 2 - vin2 NONE NONE R 2 - vin3 NONE NONE R 2 - vin4 NONE NONE R 2 - vdd_min vdd vdd RW 2 - vin1_min vin1 vin1 RW 2 - vin2_min vin2 vin2 RW 2 - vin3_min vin3 vin3 RW 2 - vin4_min vin4 vin4 RW 2 - vdd_max vdd vdd RW 2 - vin1_max vin1 vin1 RW 2 - vin2_max vin2 vin2 RW 2 - vin3_max vin3 vin3 RW 2 - vin4_max vin4 vin4 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - temp1 NONE NONE R 1 - temp2 NONE NONE R 1 - temp1_hyst temp1 temp1 RW 1 - temp2_hyst temp2 temp2 RW 1 - temp1_over temp1 temp1 RW 1 - temp2_over temp2 temp2 RW 1 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - alarms NONE NONE R 0 - beep_enable alarms NONE RW 0 - beeps alarms alarms RW 0 - two_temps NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - vdd SENSORS_GL520_VDD vdd:3 - vin1 SENSORS_GL520_VIN1 vin1:3 - vin2 SENSORS_GL520_VIN2 vin2:3 - vin3 SENSORS_GL520_VIN3 vin3:3 - vin4 SENSORS_GL520_VIN4 vin3:3 - vdd_min SENSORS_GL520_VDD_MIN vdd:1 - vin1_min SENSORS_GL520_VIN1_MIN vin1:1 - vin2_min SENSORS_GL520_VIN2_MIN vin2:1 - vin3_min SENSORS_GL520_VIN3_MIN vin3:1 - vin4_min SENSORS_GL520_VIN4_MIN vin3:1 - vdd_max SENSORS_GL520_VDD_MAX vdd:2 - vin1_max SENSORS_GL520_VIN1_MAX vin1:2 - vin2_max SENSORS_GL520_VIN2_MAX vin2:2 - vin3_max SENSORS_GL520_VIN3_MAX vin3:2 - vin4_max SENSORS_GL520_VIN4_MAX vin3:2 - fan1 SENSORS_GL520_FAN1 fan1:2 - fan2 SENSORS_GL520_FAN2 fan2:2 - fan1_min SENSORS_GL520_FAN1_MIN fan1:1 - fan2_min SENSORS_GL520_FAN2_MIN fan2:1 - temp1 SENSORS_GL520_TEMP1 temp1:3 - temp2 SENSORS_GL520_TEMP2 temp2:3 - temp1_hyst SENSORS_GL520_TEMP1_HYST temp1:2 - temp2_hyst SENSORS_GL520_TEMP2_HYST temp2:2 - temp1_over SENSORS_GL520_TEMP1_OVER temp1:1 - temp2_over SENSORS_GL520_TEMP2_OVER temp2:1 - fan1_div SENSORS_GL520_FAN1_DIV fan_div:1 - fan2_div SENSORS_GL520_FAN2_DIV fan_div:2 - alarms SENSORS_GL520_ALARMS alarms:1 - beep_enable SENSORS_GL520_BEEP_ENABLE beep:1 - beeps SENSORS_GL520_BEEPS beep:2 - two_temps SENSORS_GL520_TWOTEMPS config:1 diff --git a/doc/chips/it87 b/doc/chips/it87 deleted file mode 100644 index d33fdd92..00000000 --- a/doc/chips/it87 +++ /dev/null @@ -1,273 +0,0 @@ -Kernel driver `it87.o' -====================== - -Status: Complete, stable - -Supported chips: - * IT8705F - Prefix: 'it87' - Addresses scanned: ISA autodetected - Datasheet: Publicly available at the ITE website - http://www.ite.com.tw/ - * IT8712F - Prefix: 'it8712' - Addresses scanned: I2C 0x28 - 0x2f, ISA autodetected - Datasheet: Publicly available at the ITE website - http://www.ite.com.tw/ - * SiS950 [clone of IT8705F] - Prefix: 'it87' - Addresses scanned: ISA autodetected - Datasheet: No longer publicly available - -Author: Christophe Gauthron - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* update_vbat: integer 0 if vbat should report power on value, 1 if - vbat should be updated after each read. Default is 0. - On some boards the battery voltage is provided by either the battery or - the onboard power supply. Only the first reading at power on will be - the actual battery voltage (which the chip does automatically). On other - boards the battery voltage is always fed to the chip so can be read at - any time. Excessive reading may decrease battery life but no information - is given in the datasheet. -* reset: integer 1 if the registers of the chip should be reset at - module load time, 0 to not reset the registers. Default is 0. - - -Description ------------ - -This driver implements support for the IT8705F, IT8712F and SiS950 chips. - -These chips are 'Super I/O chips', supporting floppy disks, infrared ports, -joysticks and other miscellaneous stuff. For hardware monitoring, -they include an 'environmnent controller' with 3 temperature sensors, -3 fan rotation speed sensors, 8 voltage sensors, and associated alarms. -The IT8712F additionally features VID inputs. - -Temperatures are measured in degrees Celsius. An alarm is triggered once -when the Overtemperature Shutdown limit is crossed. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -Voltage sensors (also known as IN sensors) report their values in volts. -An alarm is triggered if the voltage has crossed a programmable minimum -or maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. All voltage -inputs can measure voltages between 0 and 4.08 volts, with a resolution -of 0.016 volt. The battery voltage in8 does not have limit registers. - -The VID lines (IT8712F only) encode the core voltage value: the voltage level -your processor should work with. This is hardcoded by the mainboard and/or -processor itself. It is a value in volts. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.5 seconds since the last update). This means that you can easily -miss once-only alarms. - -The IT87xx only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. - -The sensor type can be set at runtime as of release 2.8.2. -To change sensor N to a thermistor, 'echo 2 > sensorN' -where N is 1, 2, or 3. -To change sensor N to a thermal diode, 'echo 3 > sensorN'. -Give 0 for unused sensor. Any other value is invalid. -To configure this at startup, put the following lines in the it87 section -of /etc/sensors.conf. -(2 = thermistor; 3 = thermal diode; 0 = unused) - set sensor1 3 - set sensor2 3 - set sensor3 3 - -If you set a sensor to 0, you'll also want to ignore its value: - ignore tempN - -The fan speed control features can be enabled by setting the bits 0-2 of -the fan_ctl register to 1. (Note: bits 6-4 of this register must be set to -1 to enable the fan monitoring). - 0x40 : enable fan speed monitoring for fan3 - 0x20 : enable fan speed monitoring for fan2 - 0x10 : enable fan speed monitoring for fan1 - 0x04 : enable fan smart guardian mode for fan3 - 0x02 : enable fan smart guardian mode for fan2 - 0x01 : enable fan smart guardian mode for fan1 - -If a fan's smart guardian bit is not set this fan is in on-off mode. -It can be switched on or off by setting/clearing the corresponding bit 0-2 -of the second fan control register fan_on_off. This register has no effect if -a fan is in smart guardian mode. - 0x04 : fan3 is on - 0x02 : fan2 is on - 0x01 : fan1 is on - -Bit 7 of the pwm[1-3] registers enables/disables the chip's automatic -temperature control mode for the specified fan. If Bit 7 is set the bits -1 and 0 encode the number of the temperature sensor used for this feature. -Possible register values are: - 0x00-0x7f direct power control for the fan speed - 0x80 automatic smart guardian mode use temperature sensor 1 - 0x81 automatic smart guardian mode use temperature sensor 2 - 0x82 automatic smart guardian mode use temperature sensor 3 - -In automatic smart guardian mode pwm values for low, medium and high speed -can be set in sg_pwm[1-3]. The temperature limits for fan off, low, medium, -hi speed and over temperature are set in sg_tl[1-3]. While the sensor's -temperature is between the low and medium speed value the fan will run in -low speed. When the sensor's temperature is between the medium and high speed -value the fan spins in medium speed. When the sensor's temperature is between -the high speed and over temperature value the fan spins in high speed. -If the sensor's temperature is higher than the over temperature limit the -fan will spin with the highest possible speed. - -Example: -The preconfigured (BIOS set) values of the Shuttle XPC SN41G2 Barebone. -The MB uses temp2 to monitor the CPU temperature and fan3 as the fan for their -special ICE heatpipe cooling system. - $ cat fan_ctl - 116 - $ cat tan_on_off - 215 - $ cat pwm3 - 129 - $ cat sg_tl3 - 16.0 16.0 48.0 54.0 58.0 - $ cat sg_pwm3 - 3 4 9 - -Explanation: - fan_ctl -> 116 = 0x74 = 01110100 : fan monitoring on for all fans, - and fan3 is in smart guardian mode. - fan_on_off -> 215 = 0xd7 =11010111 : all fans are on this setting is - ignored for fan3 which is in smart guardian mode - pwm3 -> 129 = 0x81 = 10000001 : fan3 is in automatic mode and uses - temp2 for speed control - sg_tl3 -> 16.0 16.0 48.0 54.0 58.0 : off, low, med, high, and - over temperature limits of fan3 - sg_pwm3 -> 3 4 9 : pwm values for low, medium and high fan speed of fan3. - - - -Chip features -------------- - -Chip `it87` - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in5 NONE NONE R 2 - in6 NONE NONE R 2 - in7 NONE NONE R 2 - in8 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in4 in4 RW 2 - in5_min in5 in5 RW 2 - in6_min in6 in6 RW 2 - in7_min in6 in6 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in4 in4 RW 2 - in5_max in5 in5 RW 2 - in6_max in6 in6 RW 2 - in7_max in6 in6 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - fan3_min fan3 fan3 RW 0 - temp1 NONE NONE R 1 - temp2 NONE NONE R 1 - temp3 NONE NONE R 1 - temp1_low temp temp RW 1 - temp1_over temp temp RW 1 - temp2_low temp temp RW 1 - temp2_over temp temp RW 1 - temp3_low temp temp RW 1 - temp3_over temp temp RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - fan3_div fan3 NONE R 0 - alarms_vin NONE NONE R 0 - alarms_fan NONE NONE R 0 - alarms_temp NONE NONE R 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - in0 SENSORS_IT87_IN0 in0:3 - in1 SENSORS_IT87_IN1 in1:3 - in2 SENSORS_IT87_IN2 in2:3 - in3 SENSORS_IT87_IN3 in3:3 - in4 SENSORS_IT87_IN4 in4:3 - in5 SENSORS_IT87_IN5 in5:3 - in6 SENSORS_IT87_IN6 in6:3 - in7 SENSORS_IT87_IN7 in7:3 - in0_min SENSORS_IT87_IN0_MIN in0:1 - in1_min SENSORS_IT87_IN1_MIN in1:1 - in2_min SENSORS_IT87_IN2_MIN in2:1 - in3_min SENSORS_IT87_IN3_MIN in3:1 - in4_min SENSORS_IT87_IN4_MIN in4:1 - in5_min SENSORS_IT87_IN5_MIN in5:1 - in6_min SENSORS_IT87_IN6_MIN in6:1 - in7_min SENSORS_IT87_IN7_MIN in7:1 - in0_max SENSORS_IT87_IN0_MAX in0:2 - in1_max SENSORS_IT87_IN1_MAX in1:2 - in2_max SENSORS_IT87_IN2_MAX in2:2 - in3_max SENSORS_IT87_IN3_MAX in3:2 - in4_max SENSORS_IT87_IN4_MAX in4:2 - in5_max SENSORS_IT87_IN5_MAX in5:2 - in6_max SENSORS_IT87_IN6_MAX in6:2 - in7_max SENSORS_IT87_IN7_MAX in7:2 - fan1 SENSORS_IT87_FAN1 fan1:2 - fan2 SENSORS_IT87_FAN2 fan2:2 - fan3 SENSORS_IT87_FAN3 fan3:2 - fan1_min SENSORS_IT87_FAN1_MIN fan1:1 - fan2_min SENSORS_IT87_FAN2_MIN fan2:1 - fan3_min SENSORS_IT87_FAN3_MIN fan3:1 - temp1 SENSORS_IT87_TEMP1 temp1:3 - temp2 SENSORS_IT87_TEMP2 temp2:3 - temp3 SENSORS_IT87_TEMP3 temp3:3 - temp1_low SENSORS_IT87_TEMP1_LOW temp1:2 - temp1_over SENSORS_IT87_TEMP1_HIGH temp1:1 - temp2_low SENSORS_IT87_TEMP2_LOW temp2:2 - temp2_over SENSORS_IT87_TEMP2_HIGH temp2:1 - temp3_low SENSORS_IT87_TEMP3_LOW temp3:2 - temp3_over SENSORS_IT87_TEMP3_HIGH temp3:1 - vid SENSORS_IT87_VID vid:1 - fan1_div SENSORS_IT87_FAN1_DIV fan_div:1 - fan2_div SENSORS_IT87_FAN2_DIV fan_div:2 - fan3_div SENSORS_IT87_FAN3_DIV fan_div:3 - alarms_fan SENSORS_IT87_ALARMS_FAN alarms_fan:1 - alarms_vin SENSORS_IT87_ALARMS_VIN alarms_vin:1 - alarms_temp SENSORS_IT87_ALARMS_TEMP alarms_temp:1 - - diff --git a/doc/chips/lm63 b/doc/chips/lm63 deleted file mode 100644 index d40397a7..00000000 --- a/doc/chips/lm63 +++ /dev/null @@ -1,102 +0,0 @@ -Kernel driver `lm63.o' -====================== - -Status: Complete, lightly tested - -Supported chips: - * National Semiconductor LM63 - Prefix: 'lm63' - Addresses scanned: I2C 0x4c - Datasheet: Publicly available at the National Semiconductor website - http://www.national.com/pf/LM/LM63.html - - -Author: Jean Delvare - -Thanks go to Tyan and especially Alex Buckingham for setting up a remote -access to their S4882 test platform for this driver. - http://www.tyan.com/ - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_lm63: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm63' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -The LM63 is a digital temperature sensor with integrated fan monitoring -and control. - -All temperature values are given in degrees Celsius. Resolution is 1.0 -degree for the local temperature, 0.125 degree for the remote temperature. - -The fan speed is measured using a tachometer. Contrary to most chips which -store the value in an 8-bit register and have a selectable clock divider -to make sure that the result will fit in the register, the LM63 uses 16-bit -value for measuring the speed of the fan. It can measure fan speeds down to -83 RPM, at least in theory. - -Note that the pin used for fan monitoring is shared with an alert out -function. Depending on how the board designer wanted to use the chip, fan -speed monitoring will or will not be possible. The proper chip configuration -is left to the BIOS, and the driver will blindly trust it. - -A PWM output can be used to control the speed of the fan. The LM63 has two -PWM modes: manual and automatic. Automatic mode is not fully implemented yet -(you cannot define your custom pwm/temperature curve), and mode change isn't -supported either. - -The lm63 driver will not update its values more frequently than every -second; reading them more often will do no harm, but will return 'old' -values. - - -Chip Features -------------- - -Chip 'lm63' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp1 - - R- 0 -temp1_high temp1 temp1 RW 0 -temp2 - - R- 3 -temp2_high temp2 temp2 RW 3 -temp2_low temp2 temp2 RW 3 -temp2_crit temp2 temp2 R- 0 -temp2_crit_hyst temp2 temp2 RW 0 -fan1 - - R- 0 -fan1_low fan1 fan1 RW 0 -pwm1 - - RW 0 -pwm1_enable pwm1 - R- 0 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp1 SENSORS_LM63_LOCAL_TEMP temp1:2 -temp1_high SENSORS_LM63_LOCAL_HIGH temp1:1 -temp2 SENSORS_LM63_REMOTE_TEMP temp2:3 -temp2_high SENSORS_LM63_REMOTE_HIGH temp2:1 -temp2_low SENSORS_LM63_REMOTE_LOW temp2:2 -temp2_crit SENSORS_LM63_REMOTE_TCRIT temp2_crit:1 -temp2_crit_hyst SENSORS_LM63_REMOTE_TCRIT_HYST temp2_crit_hyst:1 -fan1 SENSORS_LM63_FAN fan1:2 -fan1_low SENSORS_LM63_FAN_LOW fan1:1 -pwm1 SENSORS_LM63_PWM pwm1:1 -pwm1_enable SENSORS_LM63_PWM_ENABLE pwm1:2 -alarms SENSORS_LM63_ALARMS alarms:1 diff --git a/doc/chips/lm75 b/doc/chips/lm75 deleted file mode 100644 index 697ebbde..00000000 --- a/doc/chips/lm75 +++ /dev/null @@ -1,107 +0,0 @@ -Kernel driver `lm75.o' -===================== - -Status: Complete and well-tested - -Supported chips: - * National Semiconductor LM75 - Prefix: 'lm75' - Addresses scanned: I2C 0x48 - 0x4f - Datasheet: Publicly available at the National Semiconductor website - http://www.national.com/ - * Dallas Semiconductor DS75 - Prefix: 'lm75' - Addresses scanned: I2C 0x48 - 0x4f - Datasheet: Publicly available at the Maxim website - http://www.maxim-ic.com/ - * Dallas Semiconductor DS1775 - Prefix: 'lm75' - Addresses scanned: I2C 0x48 - 0x4f - Datasheet: Publicly available at the Maxim website - http://www.maxim-ic.com/ - * Maxim MAX6625, MAX6626 - Prefix: 'lm75' - Addresses scanned: I2C 0x48 - 0x4b - Datasheet: Publicly available at the Maxim website - http://www.maxim-ic.com/ - * Microchip (TelCom) TCN75 - Prefix: 'lm75' - Addresses scanned: I2C 0x48 - 0x4f - Datasheet: Publicly available at the Microchip website - http://www.microchip.com/ - * Texas Instruments TMP100, TMP101 - Prefix: 'lm75' - Addresses scanned: I2C 0x48 - 0x4f - Datasheet: Publicly available at the TI website - http://www.ti.com/ - -Author: Frodo Looijaard - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_lm75: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm75' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -The LM75 implements one temperature sensor. Limits can be set through the -Overtemperature Shutdown register and Hysteresis register. Each value can be -set and read to half-degree accuracy. -An alarm is issued (usually to a connected LM78) when the temperature -gets higher then the Overtemperature Shutdown value; it stays on until -the temperature falls below the Hysteresis value. -All temperatures are in degrees Celsius, and are guaranteed within a -range of -55 to +125 degrees. - -The LM75 only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. - -The LM75 is usually used in combination with LM78-like chips, to measure -the temperature of the processor(s). - -The DS75, DS1775, MAX6625, MAX6626, and others are supported as well. -They are not distinguished from an LM75. While most of these chips -have three additional bits of accuracy (12 vs. 9 for the LM75), -the additional bits are not supported. Not only that, but these chips will -not be detected if not in 9-bit precision mode (use the force parameter if -needed). -The prefix in the /proc directory is still 'lm75'. - -The LM75 is essentially an industry standard; there may be other -LM75 clones not listed here, with or without various enhancements, -that are supported. - -The LM77 is not supported, contrary to what we pretended for a long time. -Both chips are simply not compatible, value encoding differs. - - -Chip Features -------------- - -Chip `lm75' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - temp SENSORS_LM75_TEMP temp:3 - temp_hyst SENSORS_LM75_TEMP_HYST temp:2 - temp_over SENSORS_LM75_TEMP_OVER temp:1 - - diff --git a/doc/chips/lm78 b/doc/chips/lm78 deleted file mode 100644 index 9151973d..00000000 --- a/doc/chips/lm78 +++ /dev/null @@ -1,337 +0,0 @@ -Kernel driver `lm78.o' -====================== - -Status: Complete and well-tested - -Supported chips: - * National Semiconductor LM78 - Prefix: 'lm78' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) - Datasheet: Publicly available at the National Semiconductor website - * National Semiconductor LM78-J - Prefix: 'lm78-j' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) - Datasheet: Publicly available at the National Semiconductor website - * National Semiconductor LM79 - Prefix: 'lm79' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) - Datasheet: Publicly available at the National Semiconductor website - -Author: Frodo Looijaard - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_lm78: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm78' chip -* force_lm78j: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm78j' chip -* force_lm79: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm79' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This driver implements support for the National Semiconductor LM78, LM78-J -and LM79. They are described as `Microprocessor System Hardware Monitors'. - -There is almost no difference between the three supported chips. Functionally, -the LM78 and LM78-J are exactly identical. The LM79 has one more VID line, -which is used to report the lower voltages newer Pentium processors use. -From here on, LM7* means either of these three types. - -The LM7* implements one temperature sensor, three fan rotation speed sensors, -seven voltage sensors, VID lines, alarms, and some miscellaneous stuff. - -Temperatures are measured in degrees Celsius. An alarm is triggered once -when the Overtemperature Shutdown limit is crossed; it is triggered again -as soon as it drops below the Hysteresis value. A more useful behaviour -can be found by setting the Hysteresis value to +127 degrees Celsius; in -this case, alarms are issued during all the time when the actual temperature -is above the Overtemperature Shutdown value. Measurements are guaranteed -between -55 and +125 degrees, with a resolution of 1 degree. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -Voltage sensors (also known as IN sensors) report their values in volts. -An alarm is triggered if the voltage has crossed a programmable minimum -or maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. All voltage -inputs can measure voltages between 0 and 4.08 volts, with a resolution -of 0.016 volt. - -The VID lines encode the core voltage value: the voltage level your processor -should work with. This is hardcoded by the mainboard and/or processor itself. -It is a value in volts. When it is unconnected, you will often find the -value 3.50 V here. - -In addition to the alarms described above, there are a couple of additional -ones. There is a BTI alarm, which gets triggered when an external chip has -crossed its limits. Usually, this is connected to all LM75 chips; if at -least one crosses its limits, this bit gets set. The CHAS alarm triggers -if your computer case is open. The FIFO alarms should never trigger; it -indicates an internal error. The SMI_IN alarm indicates some other chip -has triggered an SMI interrupt. As we do not use SMI interrupts at all, -this condition usually indicates there is a problem with some other -device. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.5 seconds since the last update). This means that you can easily -miss once-only alarms. - -The LM7* only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. - - -Chip features -------------- - -Chip `lm78' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in5 NONE NONE R 2 - in6 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in4 in4 RW 2 - in5_min in5 in5 RW 2 - in6_min in6 in6 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in4 in4 RW 2 - in5_max in5 in5 RW 2 - in6_max in6 in6 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - fan3_min fan3 fan3 RW 0 - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - fan3_div fan3 NONE R 0 - alarms NONE NONE R 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - in0 SENSORS_LM78_IN0 in0:3 - in1 SENSORS_LM78_IN1 in1:3 - in2 SENSORS_LM78_IN2 in2:3 - in3 SENSORS_LM78_IN3 in3:3 - in4 SENSORS_LM78_IN4 in4:3 - in5 SENSORS_LM78_IN5 in5:3 - in6 SENSORS_LM78_IN6 in6:3 - in0_min SENSORS_LM78_IN0_MIN in0:1 - in1_min SENSORS_LM78_IN1_MIN in1:1 - in2_min SENSORS_LM78_IN2_MIN in2:1 - in3_min SENSORS_LM78_IN3_MIN in3:1 - in4_min SENSORS_LM78_IN4_MIN in4:1 - in5_min SENSORS_LM78_IN5_MIN in5:1 - in6_min SENSORS_LM78_IN6_MIN in6:1 - in0_max SENSORS_LM78_IN0_MAX in0:2 - in1_max SENSORS_LM78_IN1_MAX in1:2 - in2_max SENSORS_LM78_IN2_MAX in2:2 - in3_max SENSORS_LM78_IN3_MAX in3:2 - in4_max SENSORS_LM78_IN4_MAX in4:2 - in5_max SENSORS_LM78_IN5_MAX in5:2 - in6_max SENSORS_LM78_IN6_MAX in6:2 - fan1 SENSORS_LM78_FAN1 fan1:2 - fan2 SENSORS_LM78_FAN2 fan2:2 - fan3 SENSORS_LM78_FAN3 fan3:2 - fan1_min SENSORS_LM78_FAN1_MIN fan1:1 - fan2_min SENSORS_LM78_FAN2_MIN fan2:1 - fan3_min SENSORS_LM78_FAN3_MIN fan3:1 - temp SENSORS_LM78_TEMP temp:3 - temp_hyst SENSORS_LM78_TEMP_HYST temp:2 - temp_over SENSORS_LM78_TEMP_OVER temp:1 - vid SENSORS_LM78_VID vid:1 - fan1_div SENSORS_LM78_FAN1_DIV fan_div:1 - fan2_div SENSORS_LM78_FAN2_DIV fan_div:2 - fan3_div SENSORS_LM78_FAN3_DIV fan_div:3 - alarms SENSORS_LM78_ALARMS alarms:1 - - -Chip `lm78-j' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in5 NONE NONE R 2 - in6 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in4 in4 RW 2 - in5_min in5 in5 RW 2 - in6_min in6 in6 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in4 in4 RW 2 - in5_max in5 in5 RW 2 - in6_max in6 in6 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - fan3_min fan3 fan3 RW 0 - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - fan3_div fan3 NONE R 0 - alarms NONE NONE R 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - in0 SENSORS_LM78J_IN0 in0:3 - in1 SENSORS_LM78J_IN1 in1:3 - in2 SENSORS_LM78J_IN2 in2:3 - in3 SENSORS_LM78J_IN3 in3:3 - in4 SENSORS_LM78J_IN4 in4:3 - in5 SENSORS_LM78J_IN5 in5:3 - in6 SENSORS_LM78J_IN6 in6:3 - in0_min SENSORS_LM78J_IN0_MIN in0:1 - in1_min SENSORS_LM78J_IN1_MIN in1:1 - in2_min SENSORS_LM78J_IN2_MIN in2:1 - in3_min SENSORS_LM78J_IN3_MIN in3:1 - in4_min SENSORS_LM78J_IN4_MIN in4:1 - in5_min SENSORS_LM78J_IN5_MIN in5:1 - in6_min SENSORS_LM78J_IN6_MIN in6:1 - in0_max SENSORS_LM78J_IN0_MAX in0:2 - in1_max SENSORS_LM78J_IN1_MAX in1:2 - in2_max SENSORS_LM78J_IN2_MAX in2:2 - in3_max SENSORS_LM78J_IN3_MAX in3:2 - in4_max SENSORS_LM78J_IN4_MAX in4:2 - in5_max SENSORS_LM78J_IN5_MAX in5:2 - in6_max SENSORS_LM78J_IN6_MAX in6:2 - fan1 SENSORS_LM78J_FAN1 fan1:2 - fan2 SENSORS_LM78J_FAN2 fan2:2 - fan3 SENSORS_LM78J_FAN3 fan3:2 - fan1_min SENSORS_LM78J_FAN1_MIN fan1:1 - fan2_min SENSORS_LM78J_FAN2_MIN fan2:1 - fan3_min SENSORS_LM78J_FAN3_MIN fan3:1 - temp SENSORS_LM78J_TEMP temp:3 - temp_hyst SENSORS_LM78J_TEMP_HYST temp:2 - temp_over SENSORS_LM78J_TEMP_OVER temp:1 - vid SENSORS_LM78J_VID vid:1 - fan1_div SENSORS_LM78J_FAN1_DIV fan_div:1 - fan2_div SENSORS_LM78J_FAN2_DIV fan_div:2 - fan3_div SENSORS_LM78J_FAN3_DIV fan_div:3 - alarms SENSORS_LM78J_ALARMS alarms:1 - - -Chip `lm79' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in5 NONE NONE R 2 - in6 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in4 in4 RW 2 - in5_min in5 in5 RW 2 - in6_min in6 in6 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in4 in4 RW 2 - in5_max in5 in5 RW 2 - in6_max in6 in6 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - fan3_min fan3 fan3 RW 0 - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - fan3_div fan3 NONE R 0 - alarms NONE NONE R 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - in0 SENSORS_LM79_IN0 in0:3 - in1 SENSORS_LM79_IN1 in1:3 - in2 SENSORS_LM79_IN2 in2:3 - in3 SENSORS_LM79_IN3 in3:3 - in4 SENSORS_LM79_IN4 in4:3 - in5 SENSORS_LM79_IN5 in5:3 - in6 SENSORS_LM79_IN6 in6:3 - in0_min SENSORS_LM79_IN0_MIN in0:1 - in1_min SENSORS_LM79_IN1_MIN in1:1 - in2_min SENSORS_LM79_IN2_MIN in2:1 - in3_min SENSORS_LM79_IN3_MIN in3:1 - in4_min SENSORS_LM79_IN4_MIN in4:1 - in5_min SENSORS_LM79_IN5_MIN in5:1 - in6_min SENSORS_LM79_IN6_MIN in6:1 - in0_max SENSORS_LM79_IN0_MAX in0:2 - in1_max SENSORS_LM79_IN1_MAX in1:2 - in2_max SENSORS_LM79_IN2_MAX in2:2 - in3_max SENSORS_LM79_IN3_MAX in3:2 - in4_max SENSORS_LM79_IN4_MAX in4:2 - in5_max SENSORS_LM79_IN5_MAX in5:2 - in6_max SENSORS_LM79_IN6_MAX in6:2 - fan1 SENSORS_LM79_FAN1 fan1:2 - fan2 SENSORS_LM79_FAN2 fan2:2 - fan3 SENSORS_LM79_FAN3 fan3:2 - fan1_min SENSORS_LM79_FAN1_MIN fan1:1 - fan2_min SENSORS_LM79_FAN2_MIN fan2:1 - fan3_min SENSORS_LM79_FAN3_MIN fan3:1 - temp SENSORS_LM79_TEMP temp:3 - temp_hyst SENSORS_LM79_TEMP_HYST temp:2 - temp_over SENSORS_LM79_TEMP_OVER temp:1 - vid SENSORS_LM79_VID vid:1 - fan1_div SENSORS_LM79_FAN1_DIV fan_div:1 - fan2_div SENSORS_LM79_FAN2_DIV fan_div:2 - fan3_div SENSORS_LM79_FAN3_DIV fan_div:3 - alarms SENSORS_LM79_ALARMS alarms:1 diff --git a/doc/chips/lm80 b/doc/chips/lm80 deleted file mode 100644 index 7930124d..00000000 --- a/doc/chips/lm80 +++ /dev/null @@ -1,149 +0,0 @@ -Kernel driver `lm80.o' -====================== - -Status: Complete and tested - -Supported chips: - * National Semiconductor LM80 - Prefix: 'lm80' - Addresses scanned: I2C 0x20 - 0x2f - -Author: Frodo Looijaard and Philip Edelbrock - - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_lm80: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm80' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This driver implements support for the National Semiconductor LM80. -It is descibed as a `Serial Interface ACPI-Compatible Microprocessor -System Hardware Monitor'. - -The LM80 implements one temperature sensor, two fan rotation speed sensors, -seven voltage sensors, alarms, and some miscellaneous stuff. - -Temperatures are measured in degrees Celsius. There are two sets of limits -which operate independently. When the HOT Temperature Limit is crossed, -this will cause an alarm that will be reasserted until the temperature -drops below the HOT Hysteresis. The Overtemperature Shotdown (OS) limits -should work in the same way (but this must be checked; the datasheet -is unclear about this). Measurements are guaranteed between -55 and -+125 degrees. The current temperature measurement has a resolution of -0.0625 degrees; the limits have a resolution of 1 degree. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -Voltage ensors (also known as IN sensors) report their values in volts. -An alarm is triggered if the voltage has crossed a programmable minimum -or maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. All voltage -inputs can measure voltages between 0 and 2.55 volts, with a resolution -of 0.01 volt. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 2.0 seconds since the last update). This means that you can easily -miss once-only alarms. - -The LM80 only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. - - -Chip Features -------------- - -Chip `lm80' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in5 NONE NONE R 2 - in6 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in4 in4 RW 2 - in5_min in5 in5 RW 2 - in6_min in6 in6 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in4 in4 RW 2 - in5_max in5 in5 RW 2 - in6_max in6 in6 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan1_min fan1 NONE RW 0 - fan2_min fan2 NONE RW 0 - temp NONE NONE R 2 - temp_hot_hyst temp temp RW 2 - temp_hot_max temp temp RW 2 - temp_os_hyst temp temp RW 2 - temp_os_max temp temp RW 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - alarms NONE NONE R 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - in0 SENSORS_LM80_IN0 in0:3 - in1 SENSORS_LM80_IN1 in1:3 - in2 SENSORS_LM80_IN2 in2:3 - in3 SENSORS_LM80_IN3 in3:3 - in4 SENSORS_LM80_IN4 in4:3 - in5 SENSORS_LM80_IN5 in5:3 - in6 SENSORS_LM80_IN6 in6:3 - in0_min SENSORS_LM80_IN0_MIN in0:1 - in1_min SENSORS_LM80_IN1_MIN in1:1 - in2_min SENSORS_LM80_IN2_MIN in2:1 - in3_min SENSORS_LM80_IN3_MIN in3:1 - in4_min SENSORS_LM80_IN4_MIN in4:1 - in5_min SENSORS_LM80_IN5_MIN in5:1 - in6_min SENSORS_LM80_IN6_MIN in6:1 - in0_max SENSORS_LM80_IN0_MAX in0:2 - in1_max SENSORS_LM80_IN1_MAX in1:2 - in2_max SENSORS_LM80_IN2_MAX in2:2 - in3_max SENSORS_LM80_IN3_MAX in3:2 - in4_max SENSORS_LM80_IN4_MAX in4:2 - in5_max SENSORS_LM80_IN5_MAX in5:2 - in6_max SENSORS_LM80_IN6_MAX in6:2 - fan1 SENSORS_LM80_FAN1 fan1:2 - fan2 SENSORS_LM80_FAN2 fan2:2 - fan1_min SENSORS_LM80_FAN1_MIN fan1:1 - fan2_min SENSORS_LM80_FAN2_MIN fan2:1 - temp SENSORS_LM80_TEMP temp:5 - temp_hot_hyst SENSORS_LM80_TEMP_HOT_HYST temp:2 - temp_hot_max SENSORS_LM80_TEMP_HOT_MAX temp:1 - temp_os_hyst SENSORS_LM80_TEMP_OS_HYST temp:4 - temp_os_max SENSORS_LM80_TEMP_OS_MAX temp:3 - fan1_div SENSORS_LM80_FAN1_DIV fan_div:1 - fan2_div SENSORS_LM80_FAN2_DIV fan_div:2 - alarms SENSORS_LM80_ALARMS alarms:1 diff --git a/doc/chips/lm83 b/doc/chips/lm83 deleted file mode 100644 index d7f64690..00000000 --- a/doc/chips/lm83 +++ /dev/null @@ -1,156 +0,0 @@ -Kernel driver `lm83.o' -===================== - -Status: Complete and lightly tested - -Supported chips: - * National Semiconductor LM83 - Prefix: 'lm83' - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the National Semiconductor website - http://www.national.com/pf/LM/LM83.html - * National Semiconductor LM82 - Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e - Datasheet: Publicly available at the National Semiconductor website - http://www.national.com/pf/LM/LM82.html - - -Author: Jean Delvare - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_lm83: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm83' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -The LM83 is a digital temperature sensor. It senses its own temperature as -well as the temperature of up to three external diodes. The LM82 is -a stripped down version of the LM83 that only supports one external diode. -Both are compatible with many other devices such as the LM84 and all -other ADM1021 clones. The main difference between the LM83 and the LM84 -in that the later can only sense the temperature of one external diode. - -Using the adm1021 driver for a LM83 should work, but only two temperatures -will be reported instead of four. - -The LM83 is only found on a handful of motherboards. Both a confirmed -list and an unconfirmed list follow. If you can confirm or infirm the -fact that any of these motherboards do actually have an LM83, please -contact us. Note that the LM90 can easily be misdetected as a LM83. - -Confirmed motherboards: - SBS P014 - SBS PSL09 - -Unconfirmed motherboards: - Gigabyte GA-8IK1100 - Iwill MPX2 - Soltek SL-75DRV5 - -The LM82 is confirmed to have been found on most AMD Geode reference -designs and test platforms. - -The driver has been successfully tested by Magnus Forsström, who I'd -like to thank here. More testers will be of course welcome. - -The fact that the LM83 is only scarcely used can be easily explained. -Most motherboards come with more than just temperature sensors for -health monitoring. They also have voltage and fan rotation speed -sensors. This means that temperature-only chips are usually used as -secondary chips coupled with another chip such as an IT8705F or similar -chip, which provides more features. Since systems usually need three -temperature sensors (motherboard, processor, power supply) and primary -chips provide some temperature sensors, the secondary chip, if needed, -won't have to handle more than two temperatures. Thus, ADM1021 clones -are sufficent, and there is no need for a four temperatures sensor -chip such as the LM83. The only case where using an LM83 would make -sense is on SMP systems, such as the above-mentioned Iwill MPX2, -because you want an additional temperature sensor for each additional -CPU. - -On the SBS P014, this is different, since the LM83 is the only hardware -monitoring chipset. One temperature sensor is used for the motherboard -(actually measuring the LM83's own temperature), one is used for the -CPU. The two other sensors must be used to measure the temperature of -two other points of the motherboard. We suspect these points to be the -north and south bridges, but this couldn't be confirmed. - -All temperature values are given in degrees Celsius. Local temperature -is given within a range of 0 to +85 degrees. Remote temperatures are -given within a range of 0 to +125 degrees. Resolution is 1.0 degree, -accuracy is guaranteed to 3.0 degrees (see the datasheet for more -details). - -Each sensor has its own high limit, but the critical limit is common to -all four sensors. There is no hysteresis mechanism as found on most -recent temperature sensors. - -The lm83 driver will not update its values more frequently than every -other second; reading them more often will do no harm, but will return -'old' values. - - -Chip Features -------------- - -Chip 'lm83' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp1 - - R- 0 -temp1_high temp1 temp1 RW 0 -temp2 - - R- 0 -temp2_high temp2 temp2 RW 0 -temp3 - - R- 0 -temp3_high temp3 temp3 RW 0 -temp4 - - R- 0 -temp4_high temp4 temp4 RW 0 -tcrit - - RW 0 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp1 SENSORS_LM83_LOCAL_TEMP temp1:2 -temp1_high SENSORS_LM83_LOCAL_HIGH temp1:1 -temp2 SENSORS_LM83_REMOTE1_TEMP temp2:2 -temp2_high SENSORS_LM83_REMOTE1_HIGH temp2:1 -temp3 SENSORS_LM83_REMOTE2_TEMP temp3:2 -temp3_high SENSORS_LM83_REMOTE2_HIGH temp3:1 -temp4 SENSORS_LM83_REMOTE3_TEMP temp4:2 -temp4_high SENSORS_LM83_REMOTE3_HIGH temp4:1 -tcrit SENSORS_LM83_TCRIT tcrit:1 -alarms SENSORS_LM83_ALARMS alarms:1 - -Chip 'lm82' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp1 - - R- 0 -temp1_high temp1 temp1 RW 0 -temp3 - - R- 0 -temp3_high temp3 temp3 RW 0 -tcrit - - RW 0 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp1 SENSORS_LM83_LOCAL_TEMP temp1:2 -temp1_high SENSORS_LM83_LOCAL_HIGH temp1:1 -temp3 SENSORS_LM83_REMOTE2_TEMP temp3:2 -temp3_high SENSORS_LM83_REMOTE2_HIGH temp3:1 -tcrit SENSORS_LM83_TCRIT tcrit:1 -alarms SENSORS_LM83_ALARMS alarms:1 diff --git a/doc/chips/lm85 b/doc/chips/lm85 deleted file mode 100644 index a0df8296..00000000 --- a/doc/chips/lm85 +++ /dev/null @@ -1,527 +0,0 @@ -Kernel driver `lm85.o' -====================== - -Status: Complete and somewhat tested - -Supported chips: - * National Semiconductor LM85 (B and C versions) - Prefix: 'lm85' - Addresses scanned: I2C 0x2c, 0x2d, 0x2e - Datasheet: http://www.national.com/pf/LM/LM85.html - * Analog Devices ADM1027 - Prefix: 'adm1027' - Addresses scanned: I2C 0x2c, 0x2d, 0x2e - Datasheet: http://www.analog.com/en/prod/0,,766_825_ADM1027,00.html - * Analog Devices ADT7463 - Prefix: 'adt7463' - Addresses scanned: I2C 0x2c, 0x2d, 0x2e - Datasheet: http://www.analog.com/en/prod/0,,766_825_ADT7463,00.html - * SMSC EMC6D100, SMSC EMC6D101 - Prefix: 'emc6d100' - Addresses scanned: I2C 0x2c, 0x2d, 0x2e - Datasheet: http://www.smsc.com/main/tools/discontinued/6d100.pdf - * SMSC EMC6D102, SMSC EMC6D101 - Prefix: 'emc6d102' - Addresses scanned: I2C 0x2c, 0x2d, 0x2e - Datasheet: http://www.smsc.com/main/catalog/emc6d102.html - -Authors: - Philip Pokorny - Frodo Looijaard - Richard Barrington - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to assume to be present. Autodetection - of the target device will still be attempted. Use one of the more - specific force directives below if this doesn't detect the device. -* force_lm85b: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm85-B' chip -* force_lm85c: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm85-C' chip -* force_adm1027: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adm1027' chip -* force_adt7463: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adt7463' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This driver implements support for the National Semiconductor LM85 -and compatible chips including the Analog Devices ADM1027 and ADT7463, -and SMSC EMC6D100, EMC6D101 and EMC6D102. - -The LM85 uses the 2-wire interface compatible with the SMBUS 2.0 -specification. Using an analog to digital converter it measures three -(3) temperatures and five (5) voltages. It has four (4) 16-bit -counters for measuring fan speed. Five (5) digital inputs are -provided for sampling the VID signals from the processor to the VRM. -Lastly, there are three (3) PWM outputs that can be used to control -fan speed. - -The voltage inputs have internal scaling resistors so that the -following voltage can be measured without external resistors: - - 2.5V, 3.3V, 5V, 12V, and CPU core voltage (2.25V) - -The temperatures measured are one internal diode, and two remote -diodes. Remote 1 is generally the CPU temperature. These inputs are -designed to measure a thermal diode like the one in a Pentium 4 -processor in a socket 423 or socket 478 package. They can also -measure temperature using a transistor like the 2N3904. - -A sophisticated control system for the PWM outputs is designed into -the LM85 that allows fan speed to be adjusted automatically based on -any of the three temperature sensors. Each PWM output is individually -adjustable and programmable. Once configured, the LM85 will adjust -the PWM outputs in response to the measured temperatures without -further host intervention. This feature can also be disabled for -manual control of the PWM's. - -Each of the measured inputs (voltage, temperature, fan speed) has -corresponding high/low limit values. The LM85 will signal an ALARM if -any measured value exceeds either limit. - -The LM85 samples all inputs continuously. The lm85 driver will not -read the registers more often than once a second. Further, configuration -data is only read once each 5 minutes. There is twice as much config -data as measurements, so this would seem to be a worthwhile -optimization. - -Special Features - -The LM85 has four fan speed monitoring modes. The ADM1027 has only -two. Both have special circuitry to compensate for PWM interactions -with the TACH signal from the fans. The ADM1027 can be configured to -measure the speed of a two wire fan, but the input conditioning -circuitry is different for 3-wire and 2-wire mode. For this reason, -the 2-wire fan modes are not exposed to user control. The BIOS should -initialize them to the correct mode. If you've designed your own -ADM1027, you'll have to modify the init_client function and add an -insmod parameter to set this up. - -To smooth the response of fans to changes in temperature, the LM85 has -an optional filter for smoothing temperatures. The ADM1027 has the -same config option but uses it to rate limit the changes to fan speed -instead. In libsensors, we associate the smoothing feature with a -zone in the LM85 and with a PWM in the ADM1027. - -The ADM1027 and ADT7463 have a 10-bit ADC and can therefore measure -temperatures with 0.25 degC resolution. They also provide an offset to -the temperature readings that is automatically applied during -measurement. This offset can be used to zero out any errors due to -traces and placement. The documentation says that the offset is in -0.25 degC steps, but in initial testing of the ADM1027 it was 1.00 -degC steps. Analog Devices has confirmed this "bug". The ADT7463 is -reported to work as described in the documentation. Accordingly, the -driver currently reports 1.00 degC steps for the ADM1027 and 0.25 degC -steps for the ADT7463. If you have an ADT7463, please confirm to the -LM85 maintainer that the temperature offset works as implemented. - -The ADT7463 has a THERM asserted counter. This counter has a 22.76ms -resolution and a range of 5.8 seconds. The driver implements a 31-bit -accumulator of the counter value to extend the range to over a year. -The counter will stay at it's max value until read. If you want to -insure no counts get lost, you need to trigger the driver to read the -counter every 5 seconds. You can do this by reading just the -therm_signal value. The driver implements reads of 'therm_signal' -without reading the other values for speed. A background shell script -like: - - #!/bin/bash - while [ 1 ] ; do - cat /proc/sys/dev/sensors/adt7463-*/therm_signal > /dev/null - sleep 5 - done - -Or if you want to record the values: - - #!/bin/bash - last=0 - while [ 1 ] ; do - read tlim total ovfl < /proc/sys/dev/sensors/adt7463-*/therm_signal - if [ $total -gt $last ]; then - echo $(date) - $tlim $total $ovfl - last=$total - fi - sleep 5; - done - -Either script should insure no counts are lost. - -See the vendor datasheets for more information. There is application -note from National (AN-1260) with some additional information about -the LM85. The Analog Devices datasheet is very detailed and describes -a procedure for determining an optimal configuration for the automatic -PWM control. - -Hardware Configurations ------------------------ - -The LM85 can be jumpered for 3 different SMBus addresses. There are -no other hardware configuration options for the LM85. - -The lm85 driver detects both LM85B and LM85C revisions of the chip. -See the datasheet for a complete description of the differences. -Other than identifying the chip, the driver behaves no differently -with regard to these two chips. The LM85B is recommended for new -designs. - -The ADM1027 and ADT7463 chips have an optional SMBALERT output that -can be used to signal the chipset in case a limit is exceeded or the -temperature sensors fail. Individual sensor interrupts can be masked -with 'alarm_mask' so they won't trigger SMBALERT. The SMBALERT output -if configured replaces one of the other functions (PWM2 or IN0). The -driver will print a message if the BIOS has configured this option -when the chip is detected. - -The ADT7463 also has an optional THERM output/input which can be -connected to the processor PROC_HOT output. If available, the autofan -control dynamic Tmin feature can be enabled to keep the system -temperature within spec (just?!) with the least possible fan noise. - -Configuration Notes -------------------- - -The voltage, temperature and fan inputs are available in libsensors -and the sensors executable. In addition, the automatic control of the -PWM outputs can also be configured via sensors.conf. This -configuration is described below: - -* Temperatures and Zones - -Each temperature sensor is associated with a Zone. There are three -sensors and therefore three zones. Each zone has the following -temperature configuration points: - - Limit temp -- Temperature at which the fan will turn on - [ absolute deg C from 0.0 to 127.0 ] - [ sensors.conf: zone#_limit ] - Hysteresis -- Degrees below the limit that fan will remain - on before turning off. - [ relative C from 0.0 to -15.0 ] - [ sensors.conf: zone#_hyst ] - Range -- Degrees above the limit over which the fan - PWM will be adjusted (from PWM_MIN to 100%) - [ relative deg C from 2.0 to 80.0 ] - [ sensors.conf: zone#_range ] - Critical temp -- Temperature above which other fans will be - forced to 100% PWM - [ absolute deg C from 0.0 to 127.0 ] - [ sensors.conf: zone#_critical ] - -** Temperature Range for a Zone - -The RANGE value for a given zone can have one of 16 different values -in an approximately logrithmic spacing: -Selecting a RANGE not in this list will cause the next larger range to -be used. - - Temperature ranges: 2.0, 2.5, 3.3, 4.0, 5.0, 6.6, 8.0, 10.0, - (in deg C) 13.3, 16.0, 20.0, 26.6, 32.0, 40.0, 53.3, - 80.0 - -* Temperature Smoothing or Acoustic Enhancement - -The LM85 and ADM1027 use this value in different ways. In the LM85 -it's used to filter the temperature input of a zone. In this way, it -affects all PWM's controlled by that zone temperature. In the -ADM1027, it limits the rate of change in fan speed. Thus it is part -of the PWM control algorithm. - - Smooth filter -- Optional filter constant to smooth the system - response to temperature spikes. It either - filters the measured temperatures or limits the - rate of change of fan speed. This improves - the system by limiting rapid changes in fan - speed. - [ seconds from 0.8 to 35.0 or 0.0 for OFF ] - [ sensors.conf: zone#_smooth or pwm#_smooth ] - -The smoothing can be disabled, or enabled and set to one of the values -listed below. Selecting a filter time constant not on this list will -cause the next smaller value to be used. Setting the time constant to -0 will disable the filtering. - - Filter time constant: 35.0, 17.6, 11.8, 7.0, 4.4, 3.0, 1.6, 0.8 - (in seconds) - -* PWM Control - -There are three PWM outputs. The LM85 datasheet suggests that the -pwm3 output control both fan3 and fan4. Each PWM can be individually -configured and assigned to a zone for it's control value. Each PWM can be -configured individually according to the following options. - - Spinup time -- When turning on a fan that was off, the PWM will - temporarily be set to 100% for this length of - time to insure the fan starts spinning. - [ seconds from 0.0 to 4.0 ] - [ sensors.conf: pwm#_spinup ] - Minimum PWM -- This is the PWM value at the limit temp of the - referenced zone. - [ PWM value from 0.0 to 255.0 ] - [ sensors.conf: pwm#_min ] - Frequency -- This is the base frequency of the PWM output. - [ Hz from 10.0 to 98.0 ] - [ sensors.conf: pwm#_freq ] - Min/Off flag -- This flag determines if the PWM will be off or - "min PWM" below the limit temperature. - [ 0.0 means PWM off (0%) below limit ] - [ sensors.conf: pwm#_min_ctl ] - Invert flag -- This flag causes the PWM output to be inverted. - If inverted, a PWM setting of 0 will be full on - and 100 will be off. - [ 0.0 means PWM is "normal" ] - [ sensors.conf: pwm#_invert ] - -** Spinup Time - -Spinup time can be one of eight (8) values. Selecting a spinup time -not on this list will result in the next larger spinup time being -selected. Note, the value 0.2 actually results in a setting of 0.250 -seconds. - - Spinup Time 0.0, 0.1, 0.2, 0.4, 0.7, 1.0, 2.0, 4.0 - (in seconds) - -** PWM Frequency - -The base frequency of the PWM can be controlled. The frequency can be -set to one of the following 8 values. Setting the frequency to a -value not on this list, will result in the next higher frequency being -selected. The actual device frequency may vary slightly from this -specification as designed by the manufacturer. Consult the datasheet -for more details. - - PWM Frequency 10.0, 15.0, 23.0, 30.0, 38.0, 47.0, 62.0, 98.0 - (in Hz) - -** Min/Off Flag - -Below the temperature "Limit - Hysteresis" from the controlling zone, -the PWM can turn off (set to 0) or it can stay at the minimum PWM -value. Setting this flag to 1 will cause the PWM value to be the -"Minimum PWM" value below this limit. Setting it to 0 will set the -PWM to 0 (off) below that limit. - -NOTE: It has been reported that there is a bug in the LM85 that causes -the Min/Off flag to be associated with the zones not the PWMs. This -contradicts all the published documentation. Setting pwm#_min_ctl in -this case actually affects all PWMs controlled by zone '#'. - -** Invert Flag - -The PWM output can be inverted. This may be useful if the fan power -circuitry is inverted. (A low output turns on power and a high output -turns off power to the fan). Alternatively, if a slower fan speed is -needed for higher temperatures, this could be set. - -Setting this flag to 1 will invert the PWM output. A value of 0 -does not invert the PWM output. - -* PWM Controlling Zone selection - -PWM's can be controlled by zones according to the following -configuration choices: - - Value Meaning - ------ ------------------------------------------------ - 1 Controlled by Zone 1 - 2 Controlled by Zone 2 - 3 Controlled by Zone 3 - 23 Controlled by higher temp of Zone 2 or 3 - 123 Controlled by highest temp of Zone 1, 2 or 3 - 0 PWM alwasy 0% (off) - -1 PWM always 100% (full on) - -2 Manual control (write to 'pwm#' to set) - -These are specified in sensors.conf using 'pwm#_zone' - -* /proc Interface - -These values can also be set using the /proc interface. The following -files contain the above settings in the order listed below: - - Name Values - ---------- ---------------------------------------------------- - zone# Limit, Hysteresis, Range, Critical - pwm#_cfg Spinup, PWM at low limit, Frequency, Min/Off, Invert - pwm#_zone Control Zone choice - smooth# Filtering - -The National LM85's have two vendor specific configuration -features. Tach. mode and Spinup Control. For more details on these, -see the LM85 datasheet or Application Note AN-1260. - - Name Values - ------------ -------------------------------------------------- - tach_mode For best fan speed measurement when PWM's are in use, - the Tach Mode should be set to 2 for all three (Fan's - 3 and 4 share a config setting) config values. If - PWM's are not in use or not wired to control fan - speed, mode 0 or 1 may be better. - [ sensors.conf: fan#_tach_mode ] - spinup_ctl Setting spinup_ctl to 1 will modify the fan spinup - algorithm. Instead of setting the PWM to 100% for - the configured period of time, it will be set to 100% - until the measured RPM is greater than the RPM limit - register or the time period elapses. - [ sensors.conf: pwm#_spinup_ctl ] - -The Analog Devices ADM1027 has several vendor specific enhancements. -The number of pulses-per-rev of the fans can be set, Tach monitoring -can be optimized for PWM operation, and an offset can be applied to -the temperatures to compensate for systemic errors in the -measurements. - - Name Values - ------------ -------------------------------------------------- - tach_mode For best fan speed measurement when PWM's are in use, - the Tach Mode should be set to 0. If PWM's are not - in use or not wired to control fan speed, a mode of 1 - can be selected. This will also increase the rate - of fan speed measurement from 1 per second to 4 per - second. - [ sensors.conf: fan#_tach_mode ] - fan_ppr You can set the pulses per rev to 1, 2, 3 or 4 so - that fan speeds don't have to be scaled. - [ sensors.conf: fan#_ppr ] - temp#_offset This is the value to be added or subtracted from the - measured temperature before reporting it. This also - affects the PWM control algorithms. - [ sensors.conf: temp#_offset ] - -In addition to the ADM1027 features, the ADT7463 also has Tmin control -and THERM asserted counts. Automatic Tmin control acts to adjust the -Tmin value to maintain the measured temperature sensor at a specified -temperature. There isn't much documentation on this feature in the -ADT7463 data sheet. The following values control this feature. -(These are not available via sensors.conf) - - Enable Flag -- When set to 1, the Tmin control is enabled. When - set to 0, Tmin will remain unchanged. - [ 1 means Tmin control is enabled ] - [ sensors.conf: none ] - Control Loop -- This value sets the cycle time of the control - loop which adjusts the Tmin value. The mapping - from raw value to loop period is non-linear. - [ Raw value from 0 to 7 (4sec) ] - [ sensors.conf: none ] - Set on THERM -- If enabled, this causes the operating point to be - set from the current temperature when THERM is - asserted. If THERM is connected to a PROC_HOT - signal, this can automatically set the operating - point to the highest value that is within spec. - allowing the lowest/quietest fan speed possible. - [ 1 means set op-point on THERM asserted ] - [ sensors.conf: none ] - Target Temp -- This is the target temperature. Tmin will be - adjusted to keep the measured temperature at this - value. - [ degC -127 to 127 degC ] - [ sensors.conf: none ] - -The THERM signal monitoring has three parameters: - - THERM Limit -- How long THERM can be asserted before an ALARM is - triggered. - [ 22.7 ms counts ] - [ sensors.conf: none ] - THERM Total -- How long THERM has been asserted since the driver - was loaded. - [ 22.7 ms counts ] - [ sensors.conf: none ] - Overflows -- How many times the THERM counter was read with a - max value indicating it overflowed. - [ count ] - [ sensors.conf: none ] - -These values are available via /proc under the following names in the -listed order. - - Name Values - ------------ -------------------------------------------------- - tmin_ctl# Enable, Control Period, Set on THREM, Target - therm_signal Limit, Total, Overflows - - -* Sample sensors.conf Config File - -Here is a sample LM85 chip config for sensors.conf - ---------- cut here --------- -chip "lm85c-*" "adm1027-*" "adt7463-*" "lm85-*" "lm85b-*" - -# Voltage inputs - label in0 "V1.5" # AGP on Intel S845WD1-E - label in1 "VCore" - label in2 "V3.3" - label in3 "V5" - label in4 "V12" - -# Temperature inputs - label temp1 "CPU" - label temp2 "Board" - label temp3 "Remote" - -# Fan inputs - label fan1 "CPU_Fan" - label fan2 "Fan2" - label fan3 "Fan3" - label fan4 "Fan4" - -# PWM Outputs - label pwm1 "CPU_PWM" - label pwm2 "Fan2_PWM" - label pwm3 "Fan3_PWM" - -# Voltage scaling is done on-chip. No 'compute' directive -# should be necessary. If in0 has external scaling set -# it here. - -# compute in0 @ * 2.5, @ / 2.5 - -# Adjust fans speeds for actual pulses per rev - compute fan1 @ * 2, @ / 2 # 1 pulse per rev -# set fan1_ppr 1 # ADM1027 or ADT7463 - compute fan2 @ / 2, @ * 2 # 4 pulse per rev -# set fan2_ppr 4 # ADM1027 or ADT7463 - -# Set VRM version - set vrm 9.1 # Pentium 4 - -# Set voltage limits - set in0_min 1.5 * 0.95 - set in0_max 1.5 * 1.05 - set in1_min vid * 0.95 - set in1_max vid * 1.05 - set in2_min 3.3 * 0.95 - set in2_max 3.3 * 1.05 - set in3_min 5.0 * 0.95 - set in3_max 5.0 * 1.05 - set in4_min 12 * 0.95 - set in4_max 12 * 1.05 - -# Set Fan limits - set fan1_min 3000 - set fan2_min 3000 - set fan3_min 3000 - set fan4_min 3000 - diff --git a/doc/chips/lm87 b/doc/chips/lm87 deleted file mode 100644 index 25ebc057..00000000 --- a/doc/chips/lm87 +++ /dev/null @@ -1,150 +0,0 @@ -Kernel driver `lm87.o' -====================== - -Status: Complete and somewhat tested - -Supported chips: - * National Semiconductor LM87 - Prefix: 'lm87' - Addresses scanned: I2C 0x2c - 0x2f - Datasheet: http://www.national.com/pf/LM/LM87.html - -Authors: Frodo Looijaard , - Philip Edelbrock , - Mark Studebaker , - and Stephen Rousset - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_lm87: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm87' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This driver implements support for the National Semiconductor LM87. - -The LM87 implements up to three temperature sensors, up to two fan -rotation speed sensors, up to seven voltage sensors, alarms, and some -miscellaneous stuff. - -Temperatures are measured in degrees Celsius. Each input has a high -and low alarm settings. A high limit produces an alarm when the value -goes above it, and an alarm is also produced when the value goes below -the low limit. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -Voltage sensors (also known as IN sensors) report their values in -volts. An alarm is triggered if the voltage has crossed a programmable -minimum or maximum limit. Note that minimum in this case always means -'closest to zero'; this is important for negative voltage -measurements. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.0 second since the last update). This means that you can easily -miss once-only alarms. - -The lm87 driver only updates its values each 1.0 seconds; reading it more -often will do no harm, but will return 'old' values. - - -Hardware Configurations ------------------------ - -The LM87 has four pins which can serve one of two possible functions, -depending on the hardware configuration. These pins are: - -Vccp2/D2- (pin 17) -+2.5V(IN0)/D2+ (pin 18) -FAN1/AIN1 (pin 5) -FAN2/AIN2 (pin 6) - -The most common configuration is to use the values shown here on the -left (Vccp2, 2.5V, FAN1, and FAN2). However, for a third temperature -sensor, it is possible to do away with Vccp2 and 2.5V (IN0) for the -second external temp diode inputs. Strangely, it seems that you can -monitor the core voltage of the second processor or its temperature, -but never both at the same time. Also, either/both FAN1 and FAN2 -inputs can be substituted for aux analog inputs AIN1 and/or AIN2, -respectively. - -To adjust the driver for a hardware configuration other than the -default, simply uncomment the appropriate #defines in the -kernel/chips/lm87.c driver header, and then recompile/reinstall. -Here is a copy (as of this writing) of the header: - - ---snip-- -/* Chip configuration settings. These should be set to reflect the -HARDWARE configuration of your chip. By default (read: when all of -these are left commented out), this driver assumes that the -configuration is the same as National's defaults for the Channel Mode -register. - - Set to '1' the appropriate defines, as nessesary: - - - External temp sensors 2 (possible second CPU temp) - This will disable the 2.5V and Vccp2 readings. - Strangely, National decided that you can read the - temperature of a second CPU or its core voltage, - but not both! Comment out if FAULT is reported. */ - -/* #define LM87_EXT2 1 */ - -/* Aux analog input. When enabled, the Fan 1 reading - will be disabled */ - -/* #define LM87_AIN1 1 */ - -/* Aux analog input 2. When enabled, the Fan 2 reading - will be disabled */ - -/* #define LM87_AIN2 1 */ - -/* Internal Vcc is 5V instead of 3.3V */ - -/* #define LM87_5V_VCC 1 */ - -/* That's the end of the hardware config defines. I would have made - them insmod params, but it would be too much work. ;') */ ---snip-- - -Please note: Only adjust the #defines to reflect your HARDWARE -configuration. Otherwise some, if not all, the readings will be -wrong. Simply enabling different driver configurations does not -provide the desired readings. You must make hardware changes (which -is hard) if you really wish to get a different set of readings!! - -If you may suspect that your configuration may be different than the -default, try enabling the different #defines. If you get a 'FAULT' -when using D2, it is most likely that you don't have a second external -diode, so recomment-out the #define. If you get strange readings for -some/all of the other values when enabling a AIN, then recomment-out -that #define. - -Unfortunately, it's tough to 'detect' all hardware config's -automaticly. And, I needed to resort to using #defines instead of -insmod params to make life easier on myself. diff --git a/doc/chips/lm90 b/doc/chips/lm90 deleted file mode 100644 index 75a174aa..00000000 --- a/doc/chips/lm90 +++ /dev/null @@ -1,223 +0,0 @@ -Kernel driver `lm90.o' -====================== - -Status: Complete and well tested - -Supported chips: - * National Semiconductor LM90 - Prefix: 'lm90' - Addresses scanned: I2C 0x4c - Datasheet: Publicly available at the National Semiconductor website - http://www.national.com/pf/LM/LM90.html - * National Semiconductor LM89 - Prefix: 'lm99' - Addresses scanned: I2C 0x4c and 0x4d - Datasheet: Publicly available at the National Semiconductor website - http://www.national.com/pf/LM/LM89.html - * National Semiconductor LM99 - Prefix: 'lm99' - Addresses scanned: I2C 0x4c and 0x4d - Datasheet: Publicly available at the National Semiconductor website - http://www.national.com/pf/LM/LM99.html - * National Semiconductor LM86 - Prefix: 'lm86' - Addresses scanned: I2C 0x4c - Datasheet: Publicly available at the National Semiconductor website - http://www.national.com/pf/LM/LM86.html - * Analog Devices ADM1032 - Prefix: 'adm1032' - Addresses scanned: I2C 0x4c and 0x4d - Datasheet: Publicly available at the Analog Devices website - http://products.analog.com/products/info.asp?product=ADM1032 - * Analog Devices ADT7461 - Prefix: 'adt7461' - Addresses scanned: I2C 0x4c and 0x4d - Datasheet: Publicly available at the Analog Devices website - http://products.analog.com/products/info.asp?product=ADT7461 - Note: Only if in ADM1032 compatibility mode - * Maxim MAX6657 - Prefix: 'max6657' - Addresses scanned: I2C 0x4c - Datasheet: Publicly available at the Maxim website - http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 - * Maxim MAX6658 - Prefix: 'max6657' - Addresses scanned: I2C 0x4c - Datasheet: Publicly available at the Maxim website - http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 - * Maxim MAX6659 - Prefix: 'max6657' - Addresses scanned: I2C 0x4c and 0x4d - Datasheet: Publicly available at the Maxim website - http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 - - -Author: Jean Delvare - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_lm90: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm90' chip -* force_adm1032: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adm1032' chip -* force_lm99: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm99' chip -* force_lm86: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm86' chip -* force_max6657: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `max6657' chip -* force_adt7461: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `adt7461' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -The LM90 is a digital temperature sensor. It senses its own temperature as -well as the temperature of up to one external diode. It is compatible -with many other devices such as the LM86, the LM89, the LM99, the ADM1032, -the MAX6657, the MAX6658, and the MAX6659, all of which are supported by -this driver. Additionally, the ADT7461 is supported if found in ADM1032 -compatibility mode. - -The specificity of this family of chipsets over the ADM1021/LM84 -family is that it features critical limits with hysteresis, and an -increased resolution of the remote temperature measurement. - -The different chipsets of the family are not strictly identical, although -very similar. This driver doesn't handle any specific feature for now, -with the exception of SMBus PEC. For reference, here comes a non-exhaustive -list of specific features: - -LM90: - * Filter and alert configuration register at 0xBF. - * ALERT is triggered by temperatures over critical limits. - -LM86 and LM89: - * Same as LM90 - * Better external channel accuracy - -LM99: - * Same as LM89 - * External temperature shifted by 16 degrees down - -ADM1032: - * Consecutive alert register at 0x22. - * Conversion averaging. - * Up to 64 conversions/s. - * ALERT is triggered by open remote sensor. - * SMBus PEC support for Write Byte and Receive Byte transactions. - -ADT7461 - * Extended temperature range (breaks compatibility) - * Lower resolution for remote temperature - -MAX6657 and MAX6658: - * Remote sensor type selecion - -MAX6659 - * Selectable address - * Second critical temperature limit - -All temperature values are given in degrees Celsius. Resolution -is 1.0 degree for the local temperature, 0.125 degree for the remote -temperature. - -Each sensor has its own high and low limits, plus a critical limit. -Additionally, there is a relative hysteresis value common to both critical -values. To make life easier to user-space applications, two absolute values -are exported, one for each channel, but these values are of course linked. -Only the local hysteresis can be set from user-space, and the same delta -applies to the remote hysteresis. - -The lm90 driver will not update its values more frequently than every -other second; reading them more often will do no harm, but will return -'old' values. - - -PEC Support ------------ - -The ADM1032 is the only chip of the family which supports PEC. It does -not support PEC on all transactions though, so some care must be taken. - -When reading a register value, the PEC byte is computed and sent by the -ADM1032 chip. However, in the case of a combined transaction (SMBus Read -Byte), the ADM1032 computes the CRC value over only the second half of -the message rather than its entirety, because it thinks the first half -of the message belongs to a different transaction. As a result, the CRC -value differs from what the SMBus master expects, and all reads fail. - -For this reason, the lm90 driver will enable PEC for the ADM1032 only if -the bus supports the SMBus Send Byte and Receive Byte transaction types. -These transactions will be used to read register values, instead of -SMBus Read Byte, and PEC will work properly. - -Additionally, the ADM1032 doesn't support SMBus Send Byte with PEC. -Instead, it will try to write the PEC value to the register (because the -SMBus Send Byte transaction with PEC is similar to a Write Byte transaction -without PEC), which is not what we want. Thus, PEC is explicitly disabled -on SMBus Send Byte transactions in the lm90 driver. - -PEC on byte data transactions represents a significant increase in bandwidth -usage (+33% for writes, +25% for reads) in normal conditions. With the need -to use two SMBus transaction for reads, this overhead jumps to +50%. Worse, -two transactions will typically mean twice as much delay waiting for -transaction completion, effectively doubling the register cache refresh time. -I guess reliability comes at a price, but it's quite expensive this time. - -So, as not everyone might enjoy the slowdown, PEC can be disabled through -procfs. Just write 0 to the "pec" file and PEC will be disabled. Write 1 -to that file to enable PEC again. - - -Chip Features -------------- - -Chips 'lm90', adm1032', 'lm99', 'lm86', 'max6657' and 'adt7461' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp1 - - R- 0 -temp1_high temp1 temp1 RW 0 -temp1_low temp1 temp1 RW 0 -temp2 - - R- 1 -temp2_high temp2 temp2 RW 1 -temp2_low temp2 temp2 RW 1 -tcrit1 temp1 temp1 RW 0 -tcrit2 temp2 temp2 RW 0 -hyst1 temp1 temp1 RW 0 -hyst2 temp2 temp2 R- 0 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp1 SENSORS_LM90_LOCAL_TEMP temp1:3 -temp1_high SENSORS_LM90_LOCAL_HIGH temp1:1 -temp1_low SENSORS_LM90_LOCAL_LOW temp1:2 -temp2 SENSORS_LM90_REMOTE_TEMP temp2:3 -temp2_high SENSORS_LM90_REMOTE_HIGH temp2:1 -temp2_low SENSORS_LM90_REMOTE_LOW temp2:2 -tcrit1 SENSORS_LM90_LOCAL_TCRIT tcrit1:1 -tcrit2 SENSORS_LM90_REMOTE_TCRIT tcrit2:1 -hyst1 SENSORS_LM90_LOCAL_TCRIT_HYST hyst1:1 -hyst2 SENSORS_LM90_REMOTE_TCRIT_HYST hyst2:1 -alarms SENSORS_LM90_ALARMS alarms:1 diff --git a/doc/chips/lm92 b/doc/chips/lm92 deleted file mode 100644 index d59803c8..00000000 --- a/doc/chips/lm92 +++ /dev/null @@ -1,89 +0,0 @@ -Kernel driver `lm92.o' -====================== - -Status: Complete and somewhat tested - -Supported chips: - * National Semiconductor LM92 - Prefix: 'lm92' - Addresses scanned: I2C 0x48 - 0x4b - * National Semiconductor LM76 - Prefix: 'lm92' - Addresses scanned: none, force parameter needed - * Maxim MAX6633/MAX6634/MAX6635 - Prefix: 'lm92' - Addresses scanned: I2C 0x48 - 0x4f - MAX6633 with address in 0x40 - 0x47 needs force parameter - -Author: Abraham van der Merwe - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_lm92: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `lm92' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -This driver implements support for the National Semiconductor LM92 -temperature sensor. - -Each LM92 temperature sensor supports a single temperature sensor. -Temperatures are exported to proc in degrees Celsius * 10000 (in other -words temperatures are accurate to 4 decimal places). There are alarms -for high, low, and critical thresholds. There's also an hysteresis to -control the thresholds for resetting alarms. - -At the moment the driver controls these sensors in comparator mode and the -interrupt pins (INT, T_CRIT_A) are ignored. - -Support was added later for the LM76 and Maxim MAX6633/MAX6634/MAX6635, -which are mostly compatible. They have not all been tested, so you -may need to use the force parameter. - - -Hardware Configurations ------------------------ - -The only thing that can be changed is enabling of the fault queue. Doing so -ensures that alarms will only be triggered if 4 consecutive readings all -cross the alarm thresholds. You can enable this behaviour by uncommenting -the #define in the driver source, and then recompile/reinstall. - - -Chip Features -------------- - -Chip 'lm92' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 4 -temp_high temp temp RW 4 -temp_low temp temp RW 4 -temp_crit temp temp RW 4 -temp_hyst temp temp RW 4 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_LM92_TEMP temp:1 -temp_high SENSORS_LM92_TEMP_HIGH temp:2 -temp_low SENSORS_LM92_TEMP_LOW temp:3 -temp_crit SENSORS_LM92_TEMP_CRIT temp:4 -temp_hyst SENSORS_LM92_TEMP_HYST temp:5 -alarms SENSORS_LM92_ALARMS alarms:1 diff --git a/doc/chips/lm93 b/doc/chips/lm93 deleted file mode 100644 index ae3e5c68..00000000 --- a/doc/chips/lm93 +++ /dev/null @@ -1,386 +0,0 @@ -Kernel driver 'lm93.o' -====================== - -Status: In progress - -Supported chips: - * National Semiconductor LM93 - Prefix: 'lm93' - Addresses scanned: I2C 0x2c-0x2e - -Author: - Mark M. Hoffman - - -Module Parameters ------------------ - -(specific to LM93) -* init: integer - Set to zero to disable some initializations (default is 1) -* disable_block: integer - A "0" allows SMBus block data transactions if the host supports them. A "1" - disables SMBus block data transactions. The default is 0. -* vccp_limit_type: integer array (2) - Configures in7 and in8 limit type, where 0 means absolute and non-zero - means relative. "Relative" here refers to "Dynamic Vccp Monitoring using - VID" from the datasheet. It greatly simplifies the interface to allow - only one set of limits (absolute or relative) to be in operation at a - time (even though the hardware is capable of enabling both). There's - not a compelling use case for enabling both at once, anyway. The default - is "0,0". -* vid_agtl: integer - A "0" configures the VID pins for V(ih) = 2.1V min, V(il) = 0.8V max. - A "1" configures the VID pins for V(ih) = 0.8V min, V(il) = 0.4V max. - (The latter setting is referred to as AGTL+ Compatible in the datasheet.) - I.e. this parameter controls the VID pin input thresholds; if your VID - inputs are not working, trying changing this. The default value is "0". - -(common among sensor drivers) -* force: short array (min = 1, max = 48) - List of adapter,address pairs to assume to be present. Autodetection - of the target device will still be attempted. Use one of the more - specific force directives below if this doesn't detect the device. -* force_lm93: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a 'lm93' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Hardware Description --------------------- - -(from the datasheet) - -The LM93, hardware monitor, has a two wire digital interface compatible with -SMBus 2.0. Using an 8-bit ADC, the LM93 measures the temperature of two remote -diode connected transistors as well as its own die and 16 power supply -voltages. To set fan speed, the LM93 has two PWM outputs that are each -controlled by up to four temperature zones. The fancontrol algorithm is lookup -table based. The LM93 includes a digital filter that can be invoked to smooth -temperature readings for better control of fan speed. The LM93 has four -tachometer inputs to measure fan speed. Limit and status registers for all -measured values are included. The LM93 builds upon the functionality of -previous motherboard management ASICs and uses some of the LM85's features -(i.e. smart tachometer mode). It also adds measurement and control support -for dynamic Vccp monitoring and PROCHOT. It is designed to monitor a dual -processor Xeon class motherboard with a minimum of external components. - - -User Interface --------------- - -#PROCHOT: - -The LM93 can monitor two #PROCHOT signals. The results are found in the -/proc files prochot1 and prochot2. There are three values per file: the first -value is the user limit. The second value is the current reading for the -most recent complete time interval. The third value is something like a -2 period exponential moving average (but not quite - check the datasheet). -Note that this third value is calculated by the chip itself. All values -range from 0-255 where 0 indicates no throttling, and 255 indicates > 99.6%. - -The monitoring intervals for the two #PROCHOT signals is also configurable. -These intervals can be found in the /proc file prochot_interval. There are -two values in this file: one each for #P1_PROCHOT and #P2_PROCHOT, res- -pectively. Selecting a value not in this list will cause the driver to -use the next largest interval. The available intervals are (in seconds): - -#PROCHOT intervals: 0.73, 1.46, 2.9, 5.8, 11.7, 23.3, 46.6, 93.2, 186, 372 - -It is possible to configure the LM93 to logically short the two #PROCHOT -signals. I.e. when #P1_PROCHOT is asserted, the LM93 will automatically -assert #P2_PROCHOT, and vice-versa. This mode is enabled by writing a -non-zero integer to the /proc file prochot_short. - -The LM93 can also override the #PROCHOT pins by driving a PWM signal onto -one or both of them. When overridden, the signal has a period of 3.56 ms, -a minimum pulse width of 5 clocks (at 22.5kHz => 6.25% duty cycle), and -a maximum pulse width of 80 clocks (at 22.5kHz => 99.88% duty cycle). - -The /proc file prochot_override has three values. The first two are boolean -integers which enable/disable the override funtion for #P1_PROCHOT and -#P2_PROCHOT, the third value is 0-15 where 0 indicates minimum duty cycle -and 15 indicates maximum. - -#VRD_HOT: - -The LM93 can monitor two #VRD_HOT signals. The results are found in the -/proc files vrdhot1 and vrdhot2. There is one value per file: a boolean for -which 1 indicates #VRD_HOT is asserted and 0 indicates it is negated. These -files are read-only. - -Smart Tach Mode: - -(from the datasheet) - - If a fan is driven using a low-side drive PWM, the tachometer - output of the fan is corrupted. The LM93 includes smart tachometer - circuitry that allows an accurate tachometer reading to be - achieved despite the signal corruption. In smart tach mode all - four signals are measured within 4 seconds. - -Smart tach mode is enabled by the driver by writing 1 or 2 (associating the -the fan tachometer with a pwm) to the /proc file fan_smart_tach. A zero -will disable the function for that fan. Note that Smart tach mode cannot be -enabled if the PWM output frequency is 22500 Hz (see below). - -Manual PWM: - -The LM93 has a fixed or override mode for the two PWM outputs (although, there -are still some conditions that will override even this mode - see section -15.10.6 of the datasheet for details.) The /proc files pwm1 and pwm2 are -used to enable and control this mode. The first value of the file is an -integer (0-255) where 0 is 0% duty cycle, and 255 is 100%. The second value -is a boolean integer where 0 disables and 1 enables the manual control mode. -Note that the duty cycle values are constrained by the hardware. Selecting -a value which is not available will cause the driver to use the next largest -value. Also note: when manual PWM mode is disabled, the first value of the -/proc files indicates the current duty cycle chosen by the h/w. - -PWM Output Frequency: - -The LM93 supports several different frequencies for the PWM output channels. -The /proc files pwm1_freq and pwm2_freq are used to select the frequency. The -frequency values are constrained by the hardware. Selecting a value which is -not available will cause the driver to use the next largest value. Also note -that this parameter has implications for the Smart Tach Mode (see above). - -PWM Output Frequencies: 12, 36, 48, 60, 72, 84, 96, 22500 Hz (h/w default) - -Automatic PWM: - -The LM93 is capable of complex automatic fan control, with many different -points of configuration. To start, each PWM output can be bound to any -combination of eight control sources. The final PWM is the largest of all -individual control sources to which the PWM output is bound. - -The eight control sources are: temp1-temp4 (aka "zones" in the datasheet), -#PROCHOT 1 & 2, and #VRDHOT 1 & 2. The bindings are expressed as a bitmask -in the /proc files pwm_auto_channels, where a "1" enables the binding, and -a "0" disables it. The h/w default is 0x0f (all temperatures bound). - - 0x01 - Temp 1 - 0x02 - Temp 2 - 0x04 - Temp 3 - 0x08 - Temp 4 - 0x10 - #PROCHOT 1 - 0x20 - #PROCHOT 2 - 0x40 - #VRDHOT 1 - 0x80 - #VRDHOT 2 - -The function y = f(x) takes a source temperature x to a PWM output y. This -function of the LM93 is derived from a base temperature and a table of 12 -temperature offsets. The base temperature is expressed in degrees C in the -/proc files temp_auto_base. The offsets are expressed in cumulative -degrees C, with all 12 values in the files temp_auto_offsets. E.g. if the -base temperature is 40C: - - offset # temp_auto_offsets range pwm - 1 0 - 25.00% - 2 0 - 28.57% - 3 1 40C - 41C 32.14% - 4 1 41C - 42C 35.71% - 5 2 42C - 44C 39.29% - 6 2 44C - 46C 42.86% - 7 2 48C - 50C 46.43% - 8 2 50C - 52C 50.00% - 9 2 52C - 54C 53.57% - 10 2 54C - 56C 57.14% - 11 2 56C - 58C 71.43% - 12 2 58C - 60C 85.71% - > 60C 100.00% - -Valid offsets are in the range 0C <= x <= 7.5C in 0.5C increments. - -There is an independent base temperature for each temperature channel. Note, -however, there are only two tables of offsets: one each for temp[12] and -temp[34]. Therefore, any change to e.g. temp1_auto_offsets will also affect -temp2_auto_offsets. - -The LM93 can also apply hysteresis to the offset table, to prevent unwanted -oscillation between two steps in the offsets table. These values are found in -the /proc files temp_auto_offset_hyst. There is just one value; it has the -same representation as in temp_auto_offsets. - -If a temperature reading falls below the base value for that channel, the LM93 -will use the minimum PWM value. These values are found in the /proc files -temp_auto_pwm_min. Note, there are only two minimums: one each for temp[12] -and temp[34]. Therefore, any change to e.g. temp1_auto_pwm_min will also -affect temp2_auto_pwm_min. - -PWM Spin-Up Cycle: - -A spin-up cycle occurs when a PWM output is commanded from 0% duty cycle to -some value > 0%. The LM93 supports a minimum duty cycle during spin-up. These -values are found in the /proc files pwm_auto_spinup_min. There is one value -per file; it has the same representation as other PWM duty cycle values. The -duration of the spin-up cycle is also configurable. These values are found in -the /proc files pwm_auto_spinup_time. There is one value per file; it is -the spin-up time in seconds. The available spin-up times are constrained by -the hardware. Selecting a value which is not available will cause the driver -to use the next largest value. - -Spin-up Durations: 0 (disabled, h/w default), 0.1, 0.25, 0.4, 0.7, 1.0, 2.0, 4.0 - -#PROCHOT and #VRDHOT PWM Ramping: - -If the #PROCHOT or #VRDHOT signals are asserted while bound to a PWM output -channel, the LM93 will ramp the PWM output up to 100% duty cycle in discrete -steps. The duration of each step is configurable. There are two files, with -one value each in seconds: pwm_auto_prochot_ramp and pwm_auto_vrdhot_ramp. -The available ramp times are constrained by the hardware. Selecting a value -which is not available will cause the driver to use the next largest value. - -Ramp Times: 0 (disabled, h/w default) to 0.75 in 0.05 second intervals - -Fan Boost: - -For each temperature channel, there is a boost temperature: if the channel -exceeds this limit, the LM93 will immediately drive both PWM outputs to 100%. -This limit is expressed in degrees C in the /proc files temp_auto_boost. -There is also a hysteresis temperature for this function: after the boost -limit is reached, the temperature channel must drop below this value before -the boost function is disabled. This temperature is also expressed in degrees -C in the /proc files temp_auto_boost_hyst. - -GPIO Pins: - -The LM93 can monitor the logic level of four dedicated GPIO pins as well as the -four tach input pins. GPIO0-GPIO3 correspond to (fan) tach 1-4, respectively. -All eight GPIOs are read by reading the bitmask in the /proc file gpio. The -LSB is GPIO0, and the MSB is GPIO7. - - -LM93 Unique /proc Files ------------------------ - - file description - ------------------------------------------------------------- - - prochot limit, current, and moving average #PROCHOT % - - prochot_short enable or disable logical #PROCHOT pin short - - prochot_override force #PROCHOT assertion as PWM - - prochot_interval #PROCHOT PWM sampling interval - - vrdhot 0 means negated, 1 means asserted - - fan_smart_tach enable or disable smart tach mode - - pwm_auto_spinup_min minimum duty cycle during spin-up - - pwm_auto_spinup_time duration of spin-up - - pwm_auto_prochot_ramp ramp time per step when #PROCHOT asserted - - pwm_auto_vrdhot_ramp ramp time per step when #VRDHOT asserted - - temp_auto_base temperature channel base - - temp_auto_offsets temperature channel offsets - - temp_auto_offset_hyst - temperature channel offset hysteresis - - temp_auto_boost temperature channel boost (PWMs to 100%) limit - - temp_auto_boost_hyst temperature channel boost hysteresis - - gpio input state of 8 GPIO pins; read-only - - -Sample Configuration File -------------------------- - -Here is a sample LM93 chip config for sensors.conf: - ----------- cut here ---------- -chip "lm93-*" - -# VOLTAGE INPUTS - - # labels and scaling based on datasheet recommendations - label in1 "+12V1" - compute in1 @ * 12.945, @ / 12.945 - set in1_min 12 * 0.90 - set in1_max 12 * 1.10 - - label in2 "+12V2" - compute in2 @ * 12.945, @ / 12.945 - set in2_min 12 * 0.90 - set in2_max 12 * 1.10 - - label in3 "+12V3" - compute in3 @ * 12.945, @ / 12.945 - set in3_min 12 * 0.90 - set in3_max 12 * 1.10 - - label in4 "FSB_Vtt" - - label in5 "3GIO" - - label in6 "ICH_Core" - - label in7 "Vccp1" - - label in8 "Vccp2" - - label in9 "+3.3V" - set in9_min 3.3 * 0.90 - set in9_max 3.3 * 1.10 - - label in10 "+5V" - set in10_min 5.0 * 0.90 - set in10_max 5.0 * 1.10 - - label in11 "SCSI_Core" - - label in12 "Mem_Core" - - label in13 "Mem_Vtt" - - label in14 "Gbit_Core" - - # Assuming R1/R2 = 4.1143, and 3.3V reference - # -12V = (4.1143 + 1) * (@ - 3.3) + 3.3 - label in15 "-12V" - compute in15 @ * 5.1143 - 13.57719, (@ + 13.57719) / 5.1143 - set in15_min -12 * 0.90 - set in15_max -12 * 1.10 - - label in16 "+3.3VSB" - set in16_min 3.3 * 0.90 - set in16_max 3.3 * 1.10 - -# TEMPERATURE INPUTS - - label temp1 "CPU1" - label temp2 "CPU2" - label temp3 "LM93" - -# TACHOMETER INPUTS - - label fan1 "Fan1" - set fan1_min 3000 - label fan2 "Fan2" - set fan2_min 3000 - label fan3 "Fan3" - set fan3_min 3000 - label fan4 "Fan4" - set fan4_min 3000 - -# PWM OUTPUTS - - label pwm1 "CPU1" - label pwm2 "CPU2" - diff --git a/doc/chips/ltc1710 b/doc/chips/ltc1710 deleted file mode 100644 index 7d1b5897..00000000 --- a/doc/chips/ltc1710 +++ /dev/null @@ -1,67 +0,0 @@ -Kernel driver `ltc1710.o' -========================= - -Status: Complete and well-tested - -Supported chips: - * Linear Technologies LTC1710 - Prefix: 'ltc1710' - Addresses scanned: I2C 0x58 - 0x5a - Datasheet: Publicly available at the Linear Technologies website - -Author: Frodo Looijaard and Philip Edelbrock - - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_ltc1710: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `ltc1710' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -This is some documenation for the ltc1710 driver for the Linear -Technologies LTC1710. - -The LTC1710 is a simple dual switch device with a SMBus interface. It can -switch a supply voltage to either of its two output pins independantly -from the built-in SMBus interface. - -For each sensed LTC1710 there is a directory which looks something like: -ltc1710-i2c-1-59 - -For each directory there are the following files: - -* switch1 (LTC1710_SYSCTL_SWITCH_1) - Simply contains either a 1 or 0 depending on whether the switch is - currently turned on or off. -* switch2 (LTC1710_SYSCTL_SWITCH_2) - Works the same way as switch1, but is for the second switch. - -Some notes: The LTC1710 is a *very* simple I2C/SMBus device. It does not -support reads, so the status of the switches isn't polled, but rather -remembered. The LTC1710 has enough 'umph' to drive 300mA with only 0.4 Ohm -impedence (in an 'on' state). This works well for LEDs, or to drive other -devices (MOSFETs and such) which can multiply the switching effect. The -LTC1710 also contains an emergency over-temperature shut-off in the case -of too much current flow. Switch 2 switches the Vcc voltage on/off, but -Switch 1 switches the voltage present on pin 1 (0V to Vcc). - -This driver was written and maintained by Philip Edelbrock -. Please send comments/suggestions/corrections to him. -For more technical information on the LTC1710, please get the Acrobat PDF -from http://www.linear-tech.com/ diff --git a/doc/chips/matorb b/doc/chips/matorb deleted file mode 100644 index 8de73fcd..00000000 --- a/doc/chips/matorb +++ /dev/null @@ -1,97 +0,0 @@ -Kernel driver `matorb.o' -======================= - -Status: 'Beta', but it's so simple that it may be in its final state - -Supported devices: - * Matrix-Orbital (www.matrix-orbital.com) displays. Developed and - tested on the LCD2041V, but should work with all their displays. - Prefix: 'matorb' - Addresses scanned: I2C 0x2E - Datasheet: Publicly available at the Matrix-Orbital web site - (www.matrix-orbital.com) - -Author: Frodo Looijaard , and Philip Edelbrock - - -Main Contact: Philip Edelbrock - -Module Parameters ------------------ -(I'm not positive about these, so don't take this as granite) -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_matorb: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `bt869' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ -This driver provides access to the Matrix-Orbital display devices. These -devices are usually in the form of a small LCD (20x4 is typical) screen -which is mounted in a carrier which is then mounted into a 5.25" drive bay -of a computer. - -This driver allows the user to send any data to the display to control or -display anything which the display supports. - -For more information on the displays or of particular features/command sets -go to: - -http://www.matrix-orbital.com - - -Use ---- -To use, just redirect the base-10 ordinal value of bytes (or chars) to the -display. For example, to clear the screen and write a simple message, you -could do this: - -# To clear the screen, send byte 0xFE and the char 'X' (ordinal 88) -echo "254 88" > /proc/sys/dev/sensors/matorb*/disp - -# To display "hi there" -echo "hi there" \ - | perl -e '$_=; while (/(.)/gc) { print ord($1)," "; }' \ - > /proc/sys/dev/sensors/matorb*/disp - -I've written a simple sample program (in Perl) to display a full screen -of text (which is fed in on standard-input) to the display. It is in the -prog/matorb folder of this project. - -I think the displays are very attractive and add a neat sort of 'status' -display to things like servers. It would be very simple to either -make a script daemon (or modify the healthd provided in this project) -to display a current status of health info (voltages, fans, temps, etc.) -on the display. Let's see Windoze do *THAT*! :') - - -Issues ------- -Redirecting too long of a string (32 ordinals seem to be the max) to 'disp' -seems to cause problems. Keep things in small chunks (like lines). - -Built in functions (screen clearing, etc.) were initially planned to be -added as other device files (other than just 'disp'), but these functions -are just as easily done by sending the command sequences to disp (as shown -above when clearing the screen). This also ensures that the driver will -be compatible with all the displays. - -Detection is very poor (as of this writing, anyway). It looks for a device -at 0x2E and asumes it is a display. Unfortunately, the 'beta' firmware -the Matrix-Orbital people gave me doesn't have good detection abilities to -it (it ignores reads... it used to lock up the bus on reads, so at least -it doesn't do that any more! :'). If they provide an easy way to 'sense' -that it is a display (and what kind it is?) then I will add support for it. - -Let me know if you have problems which you can't figure out -(phil@netroedge.com). diff --git a/doc/chips/max1619 b/doc/chips/max1619 deleted file mode 100644 index 83bf5756..00000000 --- a/doc/chips/max1619 +++ /dev/null @@ -1,73 +0,0 @@ -Kernel driver `max1619.o' -========================= - -Status: New - -Supported chips: - * Maxim MAX1619 - Prefix: 'max1619' - Addresses scanned: I2C 0x18-0x1a, 0x29-0x2b, 0x4c-0x4e - Datasheet: Publicly available at the Maxim website - http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf - -Author: Alexey Fisher - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_max1619: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `max1619' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -The MAX1619 is a digital temperature sensor. It senses its own temperature as -well as the temperature of up to one external diode. - -All temperature values are given in degrees Celsius. Resolution -is 1.0 degree for the local temperature and for the remote temperature. - -Only the external sensor has high and low limits. - -The max1619 driver will not update its values more frequently than every -other second; reading them more often will do no harm, but will return -'old' values. - - -Chip Features -------------- - -Chips 'max1619' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp1 - - R- 0 -temp2 - - R- 0 -temp2_max temp2 temp2 RW 0 -temp2_min temp2 temp2 RW 0 -temp2_crit temp2 temp2 RW 0 -temp2_hyst temp2 temp2 RW 0 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp1 SENSORS_MAX1619_LOCAL_TEMP temp1:1 -temp2 SENSORS_MAX1619_REMOTE_TEMP temp2:3 -temp2_max SENSORS_MAX1619_REMOTE_HIGH temp2:1 -temp2_min SENSORS_MAX1619_REMOTE_LOW temp2:2 -temp2_crit SENSORS_MAX1619_REMOTE_HYST temp2_crit:1 -temp2_hyst SENSORS_MAX1619_REMOTE_MAX temp2_crit:2 -alarms SENSORS_MAX1619_ALARMS alarms:1 diff --git a/doc/chips/max6650 b/doc/chips/max6650 deleted file mode 100644 index bbd63d6c..00000000 --- a/doc/chips/max6650 +++ /dev/null @@ -1,125 +0,0 @@ -Sensors chip driver for MAXIM MAX6650 / MAX6651 fan controllers -=============================================================== - -Chip notes ----------- - -The MAX6651 is a fan controller. It has two distinct functions: - -1) Speed control, with feedback, for a single fan. The code can write - to a register requesting that the fan run at a certain speed, and the - chip will adjust the fan voltage until it reaches that speed. This - is called "closed loop" mode in the datasheet. - -2) Speed measurement (tachometers) for up to four fans, including the - controlled one. - -The MAX6650 is similar but only has one measurement tachometer. - -Both chips have a few general purpose i/o pins, some of which can be -configured to have special functions. At the time of writing an overview -of the chip, with links to the datasheet, can be seen at: - - http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2296/ln/en - -If that has moved searching for MAX6650 from Maxim's home page should -work. - -Driver state ------------- - -Currently the driver provides the following entries in /proc/sys/ -dev/sensors/max6650-xxx/: - -fan1 through fan4 (read only): the current measured fan speeds, in -rpm. - -speed (read/write): when written, sets the chip to closed loop mode and -sets the configured speed, in rpm, to the value written. When read returns -the configured speed, again in rpm. - -xdump (read only): returns all of the chip register values, except the -tachometers. Used for debug, and should probably go away or be conditionally -compiled. - -The MAX665x uses byte wide registers with various scaling factors and -some more or less complex equations (in the datasheet) relating register -values to real world values. The driver takes care of all of this. - -Note that the measured speed ("fan1") never exactly matches the set speed -("speed") because of the coarse resolution of the underlying registers. - -Assumptions ------------ - -The driver assumes that: - - o The MAX665x is running from its internal 254 kHz clock, not an - external clock. - - o The monitored fans produce two pulses per rotation (This same - assumption is made by Maxim throughout the datasheet.) - - o The tachometer count time (register 0x16) has been configured suitably - for the fans in use, perhaps by some boot code. The driver reads this - register to compute rpm, but never writes to it. - - o The speed controller prescale (low three bits of register 0x04) has - been configured suitably for the fans in use, perhaps by some boot - code. The driver reads these bits to compute rpm, but never changes - them. - -The driver currently never reads or writes any other configuration -(gpio config, alarms, 5V/12V setting). - -Bugs ----- - - o The driver assumes too much: it should be possible to set more of the - configuration dynamically instead of assuming that some other code has - done it. - - o It does not differentiate between a MAX6650 and a MAX6651, as I can - see no obvious way to do this. It has only been tested with a MAX6651 - so if anyone gets a board with a MAX6650 to test with maybe something - will be revealed, such as the three missing tachometer registers - returning all ones or something. (OK, so maybe I should have called - this driver max6651, and ignored the max6650 totally...) - - o The /proc names don't match the standards in doc/developers/proc, - as this chip doesn't map well to other fan controllers, - -Detection notes ---------------- - -The module will autodetect the presence of a max6650 or max6651 at any -of the four possible I2C addresses for these devices. There is no ID -register, but there are several registers with all zero bits at the -high end. The driver checks that all of these are in fact zero before -declaring the chip to be a MAX6650/1. - -sensors-detect --------------- - -Support for MAX6650/1 has been added to sensors-detect. It has been -tested as correctly detecting a MAX6651 at I2C address 0x1B. Like the -driver, it cannot yet distinguish a MAX6650 and MAX6651. - -prog/sensors ------------- - -Initial read-only support has been added to the "sensors" program. - -Testing -------- - -The driver and associated programs have been tested under Linux 2.4.18 -running on an embedded Intel XScale processor (actually an IXP425 running -in big-endian mode) with a MAX6651 chip. - -Author ------- - -John Morris (john.morris@spirentcom.com) - - diff --git a/doc/chips/maxilife b/doc/chips/maxilife deleted file mode 100644 index 800ee8c0..00000000 --- a/doc/chips/maxilife +++ /dev/null @@ -1,433 +0,0 @@ -Kernel driver `maxilife.o' -========================== - -Status: Mostly done and tested - -Supported chips: - * Hewlett Packard Maxilife Revision AS 00.01 for Single Pentium II Slot 1 - Prefix: 'maxilife-as' - Addresses scanned: I2C 0x10 - 0x14 - Datasheet: Only available under NDA - * Hewlett Packard Maxilife Revision CO 00.03 for Dual Xeon Slot 2 - Prefix: 'maxilife-co' - Addresses scanned: I2C 0x10 - 0x14 - Datasheet: Only available under NDA - * Hewlett Packard Maxilife Revision CG 00.04 for Dual Pentium II Slot 1 - Prefix: 'maxilife-cg' - Addresses scanned: I2C 0x10 - 0x14 - Datasheet: Only available under NDA - * Hewlett Packard NBA (New BIOS Architecture) for newer machines, - for example Kayak XU800 and XM600. - Prefix: 'maxilife-nba' - Addresses scanned: I2C 0x10 - 0x14 - Datasheet: Only available under NDA - -Author: Fons Rademakers - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_maxilife: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `maxilife' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* maxi_version: int - MaxiLife firmware version - - -Description ------------ - -The is the driver for the HP MaxiLife Health monitoring system -as used in the line of HP Kayak Workstation PC's. - -The driver supports the following MaxiLife firmware versions: - -0) HP KAYAK XU/XAs (Dual Pentium II Slot 1, Deschutes/Klamath) -1) HP KAYAK XU (Dual Xeon [Slot 2] 400/450 Mhz) -2) HP KAYAK XA (Pentium II Slot 1, monoprocessor) - -Currently firmware auto detection is not implemented. To use the -driver load it with the correct option for you Kayak. For example: - -insmod maxilife.o maxi_version=0 | 1 | 2 - -maxi_version=0 is the default - - -The lm75's are indeed accessable in the regular way via the lm75 module. -They worked out of the box. However, I don't use the "raw" lm75 info. -MaxiLife takes care of reading out the lm75's and converts the values to -temperatures. Compared to some of the other monitoring controllers MaxiLife -is quite advanced. It takes care of a lot of issues, like setting ranges, -raising alarms, etc. Machines with MaxiLife also have a little LCD display -on their front (lcd is at address 0x54). The idea is that later versions -of the driver will write health info on the lcd (a bit like lcdproc). - - -Note ----- -sensors-detect does not support recognition of the maxilife chips. - - -Chip Features -------------- - -Chip 'maxilife-as' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -fan1 - - R- 0 -fan2 - - R- 0 -fan3 - - R- 0 -fan1_min fan1 fan1 RW 0 -fan2_min fan2 fan2 RW 0 -fan3_min fan3 fan3 RW 0 -fan1_div fan1 - R- 0 -fan2_div fan2 - R- 0 -fan3_div fan3 - R- 0 -temp1 - - R- 1 -temp2 - - R- 1 -temp3 - - R- 1 -temp4 - - R- 1 -temp5 - - R- 1 -temp1_max temp1 temp1 R- 1 -temp2_max temp2 temp2 R- 1 -temp3_max temp3 temp3 R- 1 -temp4_max temp4 temp4 R- 1 -temp5_max temp5 temp5 R- 1 -temp1_hyst temp1 temp1 R- 1 -temp2_hyst temp2 temp2 R- 1 -temp3_hyst temp3 temp3 R- 1 -temp4_hyst temp4 temp4 R- 1 -temp5_hyst temp5 temp5 R- 1 -pll - - R- 2 -pll_min pll pll RW 2 -pll_max pll pll RW 2 -vid1 - - R- 4 -vid2 - - R- 4 -vid3 - - R- 4 -vid4 - - R- 4 -vid1_min vid1 vid1 RW 4 -vid2_min vid2 vid2 RW 4 -vid3_min vid3 vid3 RW 4 -vid4_min vid4 vid4 RW 4 -vid1_max vid1 vid1 RW 4 -vid2_max vid2 vid2 RW 4 -vid3_max vid3 vid3 RW 4 -vid4_max vid4 vid4 RW 4 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -fan1 SENSORS_MAXI_AS_FAN1 fan1:3 -fan2 SENSORS_MAXI_AS_FAN2 fan2:3 -fan3 SENSORS_MAXI_AS_FAN3 fan3:3 -fan1_min SENSORS_MAXI_AS_FAN1_MIN fan1:1 -fan2_min SENSORS_MAXI_AS_FAN2_MIN fan2:1 -fan3_min SENSORS_MAXI_AS_FAN3_MIN fan3:1 -fan1_div SENSORS_MAXI_AS_FAN1_DIV fan1:2 -fan2_div SENSORS_MAXI_AS_FAN2_DIV fan2:2 -fan3_div SENSORS_MAXI_AS_FAN3_DIV fan3:2 -temp1 SENSORS_MAXI_AS_TEMP1 temp1:3 -temp2 SENSORS_MAXI_AS_TEMP2 temp2:3 -temp3 SENSORS_MAXI_AS_TEMP3 temp3:3 -temp4 SENSORS_MAXI_AS_TEMP4 temp4:3 -temp5 SENSORS_MAXI_AS_TEMP5 temp5:3 -temp1_max SENSORS_MAXI_AS_TEMP1_MAX temp1:1 -temp2_max SENSORS_MAXI_AS_TEMP2_MAX temp2:1 -temp3_max SENSORS_MAXI_AS_TEMP3_MAX temp3:1 -temp4_max SENSORS_MAXI_AS_TEMP4_MAX temp4:1 -temp5_max SENSORS_MAXI_AS_TEMP5_MAX temp5:1 -temp1_hyst SENSORS_MAXI_AS_TEMP1_HYST temp1:2 -temp2_hyst SENSORS_MAXI_AS_TEMP2_HYST temp2:2 -temp3_hyst SENSORS_MAXI_AS_TEMP3_HYST temp3:2 -temp4_hyst SENSORS_MAXI_AS_TEMP4_HYST temp4:2 -temp5_hyst SENSORS_MAXI_AS_TEMP5_HYST temp5:2 -pll SENSORS_MAXI_AS_PLL pll:3 -pll_min SENSORS_MAXI_AS_PLL_MIN pll:1 -pll_max SENSORS_MAXI_AS_PLL_MAX pll:2 -vid1 SENSORS_MAXI_AS_VID1 vid1:3 -vid2 SENSORS_MAXI_AS_VID2 vid2:3 -vid3 SENSORS_MAXI_AS_VID3 vid3:3 -vid4 SENSORS_MAXI_AS_VID4 vid4:3 -vid1_min SENSORS_MAXI_AS_VID1_MIN vid1:1 -vid2_min SENSORS_MAXI_AS_VID2_MIN vid2:1 -vid3_min SENSORS_MAXI_AS_VID3_MIN vid3:1 -vid4_min SENSORS_MAXI_AS_VID4_MIN vid4:1 -vid1_max SENSORS_MAXI_AS_VID1_MAX vid1:2 -vid2_max SENSORS_MAXI_AS_VID2_MAX vid2:2 -vid3_max SENSORS_MAXI_AS_VID3_MAX vid3:2 -vid4_max SENSORS_MAXI_AS_VID4_MAX vid4:2 -alarms SENSORS_MAXI_AS_ALARMS alarms:1 - - -Chip 'maxilife-cg' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -fan1 - - R- 0 -fan2 - - R- 0 -fan3 - - R- 0 -fan1_min fan1 fan1 RW 0 -fan2_min fan2 fan2 RW 0 -fan3_min fan3 fan3 RW 0 -fan1_div fan1 - R- 0 -fan2_div fan2 - R- 0 -fan3_div fan3 - R- 0 -temp1 - - R- 1 -temp2 - - R- 1 -temp3 - - R- 1 -temp4 - - R- 1 -temp5 - - R- 1 -temp1_max temp1 temp1 R- 1 -temp2_max temp2 temp2 R- 1 -temp3_max temp3 temp3 R- 1 -temp4_max temp4 temp4 R- 1 -temp5_max temp5 temp5 R- 1 -temp1_hyst temp1 temp1 R- 1 -temp2_hyst temp2 temp2 R- 1 -temp3_hyst temp3 temp3 R- 1 -temp4_hyst temp4 temp4 R- 1 -temp5_hyst temp5 temp5 R- 1 -pll - - R- 2 -pll_min pll pll RW 2 -pll_max pll pll RW 2 -vid1 - - R- 4 -vid2 - - R- 4 -vid3 - - R- 4 -vid4 - - R- 4 -vid1_min vid1 vid1 RW 4 -vid2_min vid2 vid2 RW 4 -vid3_min vid3 vid3 RW 4 -vid4_min vid4 vid4 RW 4 -vid1_max vid1 vid1 RW 4 -vid2_max vid2 vid2 RW 4 -vid3_max vid3 vid3 RW 4 -vid4_max vid4 vid4 RW 4 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -fan1 SENSORS_MAXI_CG_FAN1 fan1:3 -fan2 SENSORS_MAXI_CG_FAN2 fan2:3 -fan3 SENSORS_MAXI_CG_FAN3 fan3:3 -fan1_min SENSORS_MAXI_CG_FAN1_MIN fan1:1 -fan2_min SENSORS_MAXI_CG_FAN2_MIN fan2:1 -fan3_min SENSORS_MAXI_CG_FAN3_MIN fan3:1 -fan1_div SENSORS_MAXI_CG_FAN1_DIV fan1:2 -fan2_div SENSORS_MAXI_CG_FAN2_DIV fan2:2 -fan3_div SENSORS_MAXI_CG_FAN3_DIV fan3:2 -temp1 SENSORS_MAXI_CG_TEMP1 temp1:3 -temp2 SENSORS_MAXI_CG_TEMP2 temp2:3 -temp3 SENSORS_MAXI_CG_TEMP3 temp3:3 -temp4 SENSORS_MAXI_CG_TEMP4 temp4:3 -temp5 SENSORS_MAXI_CG_TEMP5 temp5:3 -temp1_max SENSORS_MAXI_CG_TEMP1_MAX temp1:1 -temp2_max SENSORS_MAXI_CG_TEMP2_MAX temp2:1 -temp3_max SENSORS_MAXI_CG_TEMP3_MAX temp3:1 -temp4_max SENSORS_MAXI_CG_TEMP4_MAX temp4:1 -temp5_max SENSORS_MAXI_CG_TEMP5_MAX temp5:1 -temp1_hyst SENSORS_MAXI_CG_TEMP1_HYST temp1:2 -temp2_hyst SENSORS_MAXI_CG_TEMP2_HYST temp2:2 -temp3_hyst SENSORS_MAXI_CG_TEMP3_HYST temp3:2 -temp4_hyst SENSORS_MAXI_CG_TEMP4_HYST temp4:2 -temp5_hyst SENSORS_MAXI_CG_TEMP5_HYST temp5:2 -pll SENSORS_MAXI_CG_PLL pll:3 -pll_min SENSORS_MAXI_CG_PLL_MIN pll:1 -pll_max SENSORS_MAXI_CG_PLL_MAX pll:2 -vid1 SENSORS_MAXI_CG_VID1 vid1:3 -vid2 SENSORS_MAXI_CG_VID2 vid2:3 -vid3 SENSORS_MAXI_CG_VID3 vid3:3 -vid4 SENSORS_MAXI_CG_VID4 vid4:3 -vid1_min SENSORS_MAXI_CG_VID1_MIN vid1:1 -vid2_min SENSORS_MAXI_CG_VID2_MIN vid2:1 -vid3_min SENSORS_MAXI_CG_VID3_MIN vid3:1 -vid4_min SENSORS_MAXI_CG_VID4_MIN vid4:1 -vid1_max SENSORS_MAXI_CG_VID1_MAX vid1:2 -vid2_max SENSORS_MAXI_CG_VID2_MAX vid2:2 -vid3_max SENSORS_MAXI_CG_VID3_MAX vid3:2 -vid4_max SENSORS_MAXI_CG_VID4_MAX vid4:2 -alarms SENSORS_MAXI_CG_ALARMS alarms:1 - - -Chip 'maxilife-co' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -fan1 - - R- 0 -fan2 - - R- 0 -fan3 - - R- 0 -fan1_min fan1 fan1 RW 0 -fan2_min fan2 fan2 RW 0 -fan3_min fan3 fan3 RW 0 -fan1_div fan1 - R- 0 -fan2_div fan2 - R- 0 -fan3_div fan3 - R- 0 -temp1 - - R- 1 -temp2 - - R- 1 -temp3 - - R- 1 -temp4 - - R- 1 -temp5 - - R- 1 -temp1_max temp1 temp1 R- 1 -temp2_max temp2 temp2 R- 1 -temp3_max temp3 temp3 R- 1 -temp4_max temp4 temp4 R- 1 -temp5_max temp5 temp5 R- 1 -temp1_hyst temp1 temp1 R- 1 -temp2_hyst temp2 temp2 R- 1 -temp3_hyst temp3 temp3 R- 1 -temp4_hyst temp4 temp4 R- 1 -temp5_hyst temp5 temp5 R- 1 -pll - - R- 2 -pll_min pll pll RW 2 -pll_max pll pll RW 2 -vid1 - - R- 4 -vid2 - - R- 4 -vid3 - - R- 4 -vid4 - - R- 4 -vid1_min vid1 vid1 RW 4 -vid2_min vid2 vid2 RW 4 -vid3_min vid3 vid3 RW 4 -vid4_min vid4 vid4 RW 4 -vid1_max vid1 vid1 RW 4 -vid2_max vid2 vid2 RW 4 -vid3_max vid3 vid3 RW 4 -vid4_max vid4 vid4 RW 4 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -fan1 SENSORS_MAXI_CO_FAN1 fan1:3 -fan2 SENSORS_MAXI_CO_FAN2 fan2:3 -fan3 SENSORS_MAXI_CO_FAN3 fan3:3 -fan1_min SENSORS_MAXI_CO_FAN1_MIN fan1:1 -fan2_min SENSORS_MAXI_CO_FAN2_MIN fan2:1 -fan3_min SENSORS_MAXI_CO_FAN3_MIN fan3:1 -fan1_div SENSORS_MAXI_CO_FAN1_DIV fan1:2 -fan2_div SENSORS_MAXI_CO_FAN2_DIV fan2:2 -fan3_div SENSORS_MAXI_CO_FAN3_DIV fan3:2 -temp1 SENSORS_MAXI_CO_TEMP1 temp1:3 -temp2 SENSORS_MAXI_CO_TEMP2 temp2:3 -temp3 SENSORS_MAXI_CO_TEMP3 temp3:3 -temp4 SENSORS_MAXI_CO_TEMP4 temp4:3 -temp5 SENSORS_MAXI_CO_TEMP5 temp5:3 -temp1_max SENSORS_MAXI_CO_TEMP1_MAX temp1:1 -temp2_max SENSORS_MAXI_CO_TEMP2_MAX temp2:1 -temp3_max SENSORS_MAXI_CO_TEMP3_MAX temp3:1 -temp4_max SENSORS_MAXI_CO_TEMP4_MAX temp4:1 -temp5_max SENSORS_MAXI_CO_TEMP5_MAX temp5:1 -temp1_hyst SENSORS_MAXI_CO_TEMP1_HYST temp1:2 -temp2_hyst SENSORS_MAXI_CO_TEMP2_HYST temp2:2 -temp3_hyst SENSORS_MAXI_CO_TEMP3_HYST temp3:2 -temp4_hyst SENSORS_MAXI_CO_TEMP4_HYST temp4:2 -temp5_hyst SENSORS_MAXI_CO_TEMP5_HYST temp5:2 -pll SENSORS_MAXI_CO_PLL pll:3 -pll_min SENSORS_MAXI_CO_PLL_MIN pll:1 -pll_max SENSORS_MAXI_CO_PLL_MAX pll:2 -vid1 SENSORS_MAXI_CO_VID1 vid1:3 -vid2 SENSORS_MAXI_CO_VID2 vid2:3 -vid3 SENSORS_MAXI_CO_VID3 vid3:3 -vid4 SENSORS_MAXI_CO_VID4 vid4:3 -vid1_min SENSORS_MAXI_CO_VID1_MIN vid1:1 -vid2_min SENSORS_MAXI_CO_VID2_MIN vid2:1 -vid3_min SENSORS_MAXI_CO_VID3_MIN vid3:1 -vid4_min SENSORS_MAXI_CO_VID4_MIN vid4:1 -vid1_max SENSORS_MAXI_CO_VID1_MAX vid1:2 -vid2_max SENSORS_MAXI_CO_VID2_MAX vid2:2 -vid3_max SENSORS_MAXI_CG_VID3_MAX vid3:2 -vid4_max SENSORS_MAXI_CO_VID4_MAX vid4:2 -alarms SENSORS_MAXI_CO_ALARMS alarms:1 - - -Chip 'maxilife-nba' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -fan1 - - R- 0 -fan2 - - R- 0 -fan3 - - R- 0 -fan1_min fan1 fan1 RW 0 -fan2_min fan2 fan2 RW 0 -fan3_min fan3 fan3 RW 0 -fan1_div fan1 - R- 0 -fan2_div fan2 - R- 0 -fan3_div fan3 - R- 0 -temp1 - - R- 1 -temp2 - - R- 1 -temp3 - - R- 1 -temp4 - - R- 1 -temp5 - - R- 1 -temp1_max temp1 temp1 R- 1 -temp2_max temp2 temp2 R- 1 -temp3_max temp3 temp3 R- 1 -temp4_max temp4 temp4 R- 1 -temp5_max temp5 temp5 R- 1 -temp1_hyst temp1 temp1 R- 1 -temp2_hyst temp2 temp2 R- 1 -temp3_hyst temp3 temp3 R- 1 -temp4_hyst temp4 temp4 R- 1 -temp5_hyst temp5 temp5 R- 1 -pll - - R- 2 -pll_min pll pll RW 2 -pll_max pll pll RW 2 -vid1 - - R- 4 -vid2 - - R- 4 -vid3 - - R- 4 -vid4 - - R- 4 -vid1_min vid1 vid1 RW 4 -vid2_min vid2 vid2 RW 4 -vid3_min vid3 vid3 RW 4 -vid4_min vid4 vid4 RW 4 -vid1_max vid1 vid1 RW 4 -vid2_max vid2 vid2 RW 4 -vid3_max vid3 vid3 RW 4 -vid4_max vid4 vid4 RW 4 -alarms - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -fan1 SENSORS_MAXI_AS_FAN1 fan1:3 -fan2 SENSORS_MAXI_AS_FAN2 fan2:3 -fan3 SENSORS_MAXI_AS_FAN3 fan3:3 -fan1_min SENSORS_MAXI_AS_FAN1_MIN fan1:1 -fan2_min SENSORS_MAXI_AS_FAN2_MIN fan2:1 -fan3_min SENSORS_MAXI_AS_FAN3_MIN fan3:1 -fan1_div SENSORS_MAXI_AS_FAN1_DIV fan1:2 -fan2_div SENSORS_MAXI_AS_FAN2_DIV fan2:2 -fan3_div SENSORS_MAXI_AS_FAN3_DIV fan3:2 -temp1 SENSORS_MAXI_AS_TEMP1 temp1:3 -temp2 SENSORS_MAXI_AS_TEMP2 temp2:3 -temp3 SENSORS_MAXI_AS_TEMP3 temp3:3 -temp4 SENSORS_MAXI_AS_TEMP4 temp4:3 -temp5 SENSORS_MAXI_AS_TEMP5 temp5:3 -temp1_max SENSORS_MAXI_AS_TEMP1_MAX temp1:1 -temp2_max SENSORS_MAXI_AS_TEMP2_MAX temp2:1 -temp3_max SENSORS_MAXI_AS_TEMP3_MAX temp3:1 -temp4_max SENSORS_MAXI_AS_TEMP4_MAX temp4:1 -temp5_max SENSORS_MAXI_AS_TEMP5_MAX temp5:1 -temp1_hyst SENSORS_MAXI_AS_TEMP1_HYST temp1:2 -temp2_hyst SENSORS_MAXI_AS_TEMP2_HYST temp2:2 -temp3_hyst SENSORS_MAXI_AS_TEMP3_HYST temp3:2 -temp4_hyst SENSORS_MAXI_AS_TEMP4_HYST temp4:2 -temp5_hyst SENSORS_MAXI_AS_TEMP5_HYST temp5:2 -pll SENSORS_MAXI_AS_PLL pll:3 -pll_min SENSORS_MAXI_AS_PLL_MIN pll:1 -pll_max SENSORS_MAXI_AS_PLL_MAX pll:2 -vid1 SENSORS_MAXI_AS_VID1 vid1:3 -vid2 SENSORS_MAXI_AS_VID2 vid2:3 -vid3 SENSORS_MAXI_AS_VID3 vid3:3 -vid4 SENSORS_MAXI_AS_VID4 vid4:3 -vid1_min SENSORS_MAXI_AS_VID1_MIN vid1:1 -vid2_min SENSORS_MAXI_AS_VID2_MIN vid2:1 -vid3_min SENSORS_MAXI_AS_VID3_MIN vid3:1 -vid4_min SENSORS_MAXI_AS_VID4_MIN vid4:1 -vid1_max SENSORS_MAXI_AS_VID1_MAX vid1:2 -vid2_max SENSORS_MAXI_AS_VID2_MAX vid2:2 -vid3_max SENSORS_MAXI_AS_VID3_MAX vid3:2 -vid4_max SENSORS_MAXI_AS_VID4_MAX vid4:2 -alarms SENSORS_MAXI_AS_ALARMS alarms:1 diff --git a/doc/chips/mic74 b/doc/chips/mic74 deleted file mode 100644 index e115d385..00000000 --- a/doc/chips/mic74 +++ /dev/null @@ -1,57 +0,0 @@ -Kernel driver `mic74.o' -========================= - -Status: Beta - -Supported chips: - * Micrel MIC74 - Prefix: 'mic74' - Addresses scanned: I2C 0x20 - 0x27 - Datasheet: Publicly available at the Micrel website - http://www.micrel.com/ - -Authors: zebo25 - mds (cleanups and this doc) - -Module Parameters ------------------ - - -Description ------------ -The MIC74 is an 8-bit I/O expander for the I2C bus. -Semiconductors. It is designed to provide a byte I2C interface to up to 8 -separate devices. - -This device consists of a quasi-bidirectionnal port. Each of the eight I/Os -can be independently used as an input or output. - -The driver does not initialize the ports, they will be at their -power-up defaults, or however the BIOS programmed them. - -For more information see the datasheet. - - -Accessing MIC74 via /proc interface -------------------------------------- - -! Be careful ! -The chip is plainly impossible to detect ! Stupid chip. -So every chip with adress in the interval [20..27] could be -detected as an MIC74 or a PCF8574. Don't load both drivers. -If you have other chips in this address -range, the workaround is to load this module after the one -for your others chips. - -On detection, directories are created for each detected chip: - - /proc/sys/dev/sensors/mic74-<0>-<1>/ - where <0> is the bus the chip was detected on (e. g. i2c-0) - and <1> the chip address [20..27]: - ./mic74-i2c-0-27/ - -Inside these directories, there are seven files each, -one for each of the seven registers in the device. - -At this point you really need the datasheet. -It should be self-explanatory which file is for which register. diff --git a/doc/chips/mtp008 b/doc/chips/mtp008 deleted file mode 100644 index bf20c2c0..00000000 --- a/doc/chips/mtp008 +++ /dev/null @@ -1,73 +0,0 @@ -Kernel driver `mtp008.o' -========================= - -Status: Complete; Beta. - This chip is quite configurable and many settings cannot - be done through the driver. Hopefully the BIOS settings will - be correct for most motherboards. - -Supported chips: - * Myson MTP008 - Prefix: 'mtp008' - Addresses scanned: I2C 0x2c - 0x2e - Datasheet: Publicly available at the Myson website - -Author: Kris Van Hees - - -Description ------------ - -The Myson MTP008 is similar in function to the Winbond W83781D and the -National Semi LM78. See documentation for those chips for an overview. - - -The MTP008 chip has several pins that are configurable. - -The three temperature sensors are configurable via the driver -using either the /proc entries or 'set sensorx y' statements in -/etc/sensors.conf. -One temperature input is always temp1, and the sensor type is configured -with the sensor1 entry in /proc. -One input is either in4 or temp2, and is configured with the sensor2 entry. -One input is either in5 or temp3, and is configured with the sensor3 entry. - -For example, on the Tyan S1824D motherboard, -AIN4 is configured as PII temp sensor 2 and -AIN5 is hooked up to the -12V sensing circuit. - -Other Tyan motherboards (the 2510 Thunder and the Tiger 200) appear to -have different configurations. - -For the 2510, which has two MTP008 chips, each with a different -configuration, follow the instructions in the mtp008 section of -etc/sensors.conf.eg to configure 'sensors' correctly. - -The PWM outputs are configurable via the driver. -PWM values are from 0 to 255. The first value in the /proc entry is -the pwm value; the second is the enable (0 or 1). - -The fan3 and pwm1 functions share a pin. -If pwm1 is enabled than fan3 will read as 0. - -The Fan input types (2 wire or 3 wire) are configurable but -not via the driver. - -The driver now preserves pin settings that the BIOS configures. -If your BIOS did it right then the driver should work great. - -The MTP008 has sensor type selection in /proc like the Winbond W83782D. -However, the appropriate values used to make the selection are different. - -To select a sensor type, echo the value to the /proc entry, for example: - echo 1 > /proc/sys/dev/sensors/mtp008-i2c-0-2d/sensor1 -Or, use /etc/sensors.conf and add a line 'set sensor1 1', for example. -Hopefully the BIOS has set these already. - -Sensor selection is as follows: - - Value Function Valid on sensors - ----- -------- ---------------- - 1 Analog input (not for temperature sensing) 2,3 - 2 Thermistor 1,2,3 - 3 Pentium diode 1,2 diff --git a/doc/chips/pc87360 b/doc/chips/pc87360 deleted file mode 100644 index 0a866002..00000000 --- a/doc/chips/pc87360 +++ /dev/null @@ -1,184 +0,0 @@ -Kernel driver `pc87360.o' -========================= - -Status: Beta, PC87366 well tested, other chips untested. - -Supported chips: - * National Semiconductor PC87360, PC87363, PC87364, PC87365 and PC87366 - Addresses scanned: none, address read from Super I/O config space - Prefixes: 'pc87360', 'pc87363', 'pc87364', 'pc87365', 'pc87366' - Datasheets: - http://www.national.com/pf/PC/PC87360.html - http://www.national.com/pf/PC/PC87363.html - http://www.national.com/pf/PC/PC87364.html - http://www.national.com/pf/PC/PC87365.html - http://www.national.com/pf/PC/PC87366.html - -Authors: Jean Delvare - -Thanks to Sandeep Mehta, Tonko de Rooy and Daniel Ceregatti for testing. -Thanks to Rudolf Marek for helping me investigate conversion issues. - - -Module Parameters ------------------ - -init (int): - Chip initialization level: - 0: None - *1: Forcibly enable internal voltage and temperature channels, except in9 - 2: Forcibly enable all voltage and temperature channels, except in9 - 3: Forcibly enable all voltage and temperature channels, including in9 - -Note that this parameter has no effect for the PC87360, PC87363 and PC87364 -chips. - -Also note that for the PC87366, initialization levels 2 and 3 don't enable -all temperature channels, because some of them share pins with each other, -so they can't be used at the same time. - - -Description ------------ - -The National Semiconductor PC87360 Super I/O chip contains monitoring and -PWM control circuitry for two fans. The PC87363 chip is similar, and the -PC87364 chip has monitoring and PWM control for a third fan. - -The National Semiconductor PC87365 and PC87366 Super I/O chips are complete -hardware monitoring chipsets, not only controling and monitoring three fans, -but also monitoring eleven voltage inputs and two (PC87365) or up to four -(PC87366) temperatures. - -The driver assumes that no more than one chip is present, and one of the -standard Super I/O addresses is used (0x2E/0x2F or 0x4E/0x4F). - - -Fan Monitoring --------------- - -Fan rotation speeds are reported in RPM (revolutions per minute). An alarm -is triggered if the rotation speed has dropped below a programmable limit. -A different alarm is triggered if the fan speed is too low to be measured. - -Fan readings are affected by a programmable clock divider, giving the -readings more range or accuracy. Usually, users have to learn how it works, -but this driver implements dynamic clock divider selection, so you don't -have to care no more. - -For reference, here are a few values about clock dividers: - - slowest accuracy highest - measurable around 3000 accurate - divider speed (RPM) RPM (RPM) speed (RPM) - 1 1882 18 6928 - 2 941 37 4898 - 4 470 74 3464 - 8 235 150 2449 - -For the curious, here is how the values above were computed: - * slowest measurable speed: clock/(255*divider) - * accuracy around 3000 RPM: 3000^2/clock - * highest accurate speed: sqrt(clock*100) -The clock speed for the PC87360 family is 480 kHz. I arbitrarily chose 100 -RPM as the lowest acceptable accuracy. - -As mentioned above, you don't have to care about this no more. - -Note that not all RPM values can be represented, even when the best clock -divider is selected. This is not only true for the measured speeds, but -also for the programmable low limits, so don't be surprised if you try to -set, say, fan1_min to 2900 and it finaly reads 2909. - - -Fan Control ------------ - -PWM (pulse width modulation) values range from 0 to 255, with 0 meaning -that the fan is stopped, and 255 meaning that the fan goes at full speed. - -Be extremely careful when changing PWM values. Low PWM values, even -non-zero, can stop the fan, which may cause irreversible damage to your -hardware if temperature increases too much. When changing PWM values, go -step by step and keep an eye on temperatures. - -One user reported problems with PWM. Changing PWM values would break fan -speed readings. No explanation nor fix could be found. - - -Temperature Monitoring ----------------------- - -Temperatures are reported in degrees Celsius. Each temperature measured has -associated low, high and overtemperature limits, each of which triggers an -alarm when crossed. - -The first two temperature channels are external. The third one (PC87366 -only) is internal. - -The PC87366 has three additional temperature channels, based on -thermistors (as opposed to thermal diodes for the first three temperature -channels). For technical reasons, these channels are held by the VLM -(voltage level monitor) logical device, not the TMS (temperature -measurement) one. As a consequence, these temperatures are exported as -voltages, and converted into temperatures in user-space. - -Note that these three additional channels share their pins with the -external thermal diode channels, so you (physically) can't use them all at -the same time. Although it should be possible to mix the two sensor types, -the documents from National Semiconductor suggest that motherboard -manufacturers should choose one type and stick to it. So you will more -likely have either channels 1 to 3 (thermal diodes) or 3 to 6 (internal -thermal diode, and thermistors). - - -Voltage Monitoring ------------------- - -Voltages are reported relatively to a reference voltage, either internal or -external. Some of them (in7:Vsb, in8:Vdd and in10:AVdd) are divided by two -internally, you will have to compensate in sensors.conf. Others (in0 to in6) -are likely to be divided externally. The meaning of each of these inputs as -well as the values of the resistors used for division is left to the -motherboard manufacturers, so you will have to document yourself and edit -sensors.conf accordingly. National Semiconductor has a document with -recommended resistor values for some voltages, but this still leaves much -room for per motherboard specificities, unfortunately. Even worse, -motherboard manufacturers don't seem to care about National Semiconductor's -recommendations. - -Each voltage measured has associated low and high limits, each of which -triggers an alarm when crossed. - -When available, VID inputs are used to provide the nominal CPU Core voltage. -The driver will default to VRM 9.0, but this can be changed from user-space. -The chipsets can handle two sets of VID inputs (on dual-CPU systems), but -the driver will only export one for now. This may change later if there is -a need. - - -General Remarks ---------------- - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may already -have disappeared! Note that all hardware registers are read whenever any -data is read (unless it is less than 2 seconds since the last update, in -which case cached values are returned instead). As a consequence, when -a once-only alarm triggers, it may take 2 seconds for it to show, and 2 -more seconds for it to disappear. - -Monitoring of in9 isn't enabled at lower init levels (<3) because that -channel measures the battery voltage (Vbat). It is a known fact that -repeatedly sampling the battery voltage reduces its lifetime. National -Semiconductor smartly designed their chipset so that in9 is sampled only -once every 1024 sampling cycles (that is every 34 minutes at the default -sampling rate), so the effect is attenuated, but still present. - - -Limitations ------------ - -The datasheets suggests that some values (fan mins, fan dividers) -shouldn't be changed once the monitoring has started, but we ignore that -recommendation. We'll reconsider if it actually causes trouble. diff --git a/doc/chips/pca9540 b/doc/chips/pca9540 deleted file mode 100644 index d810dbc5..00000000 --- a/doc/chips/pca9540 +++ /dev/null @@ -1,76 +0,0 @@ -Kernel driver `pca9540.o' -========================= - -Status: Complete but untested - -Supported chips: - * Philips PCA9540 - Prefix: 'pca9540' - Addresses scanned: I2C 0x70 - Datasheet: Publicly available at the Philips Semiconductors website - http://www.semiconductors.philips.com/pip/PCA9540.html - -Authors: Jean Delvare - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_pca9540: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to - contain a `pca9540' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - -Note that the force and force_pca9540 parameters are equivalent here. - - -Description (from the Philips web site) ---------------------------------------- - -The PCA9540 is a 1-of-2 bi-directional translating multiplexer, controlled -via the I2C bus. The SCL/SDA upstream pair fans out to two SCL/SDA downstream -pairs, or channels. Only one SCL/SDA channel is selected at a time, -determined by the contents of the programmable control register. - - -Accessing the PCA9540 ---------------------- - -The PCA9540 is almost impossible to detect. We are lucky that no other -known chip lives at address 0x70. - -Beware that the PCA9540 has a single internal register. It does work with -READ BYTE and WRITE BYTE commands, contrary to regular chips which use -READ BYTE DATA and WRITE BYTE DATA. Using i2cdump on the PCA9540 will -actually *write* to it and leave its internal register to value 0x07 (i.e. -no downstream channel selected). - - -/proc Interface ---------------- - -There is a single read/write file, named "channel". - - 0 = no downstream channel selected - 1 = first downstream channel selected - 2 = second downstream channel selected - - -Chip Features -------------- - -Chip `pca9540' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - channel NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - channel SENSORS_PCA9540_CHANNEL channel:1 diff --git a/doc/chips/pcf8574 b/doc/chips/pcf8574 deleted file mode 100644 index 744beebf..00000000 --- a/doc/chips/pcf8574 +++ /dev/null @@ -1,100 +0,0 @@ -Kernel driver `pcf8574.o' -========================= - -Status: Complete - -Supported chips: - * Philips PCF8574 - Prefix: 'pcf8574' - Addresses scanned: I2C 0x20 - 0x27 - Datasheet: Publicly available at the Philips Semiconductors website - http://www.semiconductors.philips.com/pip/PCF8574P.html - - * Philips PCF8574A - Prefix: 'pcf8574a' - Addresses scanned: I2C 0x38 - 0x3f - Datasheet: Publicly available at the Philips Semiconductors website - http://www.semiconductors.philips.com/pip/PCF8574P.html - -Authors: Frodo Looijaard , - Philip Edelbrock , - and Dan Eaton - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_pcf8574: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to - contain a `pcf8574' chip -* force_pcf8574a: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to - contain a `pcf8574a' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ -The PCF8574(A) is an 8-bit I/O expander for the I2C bus produced by Philips -Semiconductors. It is designed to provide a byte I2C interface to up to 16 -separate devices (8 x PCF8574 and 8 x PCF8574A). - -This device consists of a quasi-bidirectionnal port. Each of the eight I/Os -can be independently used as an input or output. To setup an I/O as an -input, you have to write a 1 to the corresponding output. - -For more informations see the datasheet. - - -Accessing PCF8574(A) via /proc interface -------------------------------------- - -! Be careful ! -The PCF8574(A) is plainly impossible to detect ! Stupid chip. -So every chip with adress in the interval [20..27] and [38..3f] is -detected as PCF8574(A). If you have other chips in this address -range, the workaround is to load this module after the one -for your others chips. - -On detection (i.e. insmod, modprobe et al.), directories are being -created for each detected PCF8574(A): - -/proc/sys/dev/sensors/pcf8574-<0>-<1>/ -where <0> is the bus the chip was detected on (e. g. i2c-0) -and <1> the chip address ([20..27] or [38..3f]): -./pcf8574-i2c-0-27/ - -Inside these directories, there are two files each: -read and write. - -The read file is read-only. Reading gives you the current I/O input -if the corresponding output is set as 1, otherwise the current output -value, that is to say 0. - -The write file is read/write. Writing a value outputs it on the I/O -port. Reading return the last written value. - -On module initialization the chip is configured as eight inputs (all -outputs to 1), so you can connect any circuit to the PCF8574(A) without -being afraid of short-circuit. - - -Chip Features -------------- - -Chip `pcf8574' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - read NONE NONE R 0 - write NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - read SENSORS_PCF8591_READ read:1 - write SENSORS_PCF8591_WRITE write:1 diff --git a/doc/chips/pcf8591 b/doc/chips/pcf8591 deleted file mode 100644 index 71123adb..00000000 --- a/doc/chips/pcf8591 +++ /dev/null @@ -1,127 +0,0 @@ -Kernel driver `pcf8591.o' -======================== - -Status: Status: Complete; Beta. - -Supported chips: - * Philips PCF8591 - Prefix: 'pcf8591' - Addresses scanned: I2C 0x48 - 0x4f - Datasheet: Publicly available at the Philips Semiconductors website - http://www.semiconductors.philips.com/pip/PCF8591P.html - -Author: Aurelien Jarno -valuable contributions by Jan M. Sendler - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_pcf8591: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to - contain a `pcf8591' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ -The PCF8591 is an 8-bit A/D and D/A converter (4 analog inputs and one -analog ouput) for the I2C bus produced by Philips Semiconductors. It -is designed to provide a byte I2C interface to up to 4 separate devices. - -The PCF8591 has 4 analog inputs programmable as single-ended or -differential inputs : -- mode 0 : four single ended inputs - Pins AIN0 to AIN3 are single ended inputs for channels 0 to 3 - -- mode 1 : three differential inputs - Pins AIN3 is the common negative differential input - Pins AIN0 to AIN2 are positive differential inputs for channels 0 to 2 - -- mode 2 : single ended and differential mixed - Pins AIN0 and AIN1 are single ended inputs for channels 0 and 1 - Pins AIN2 is the positive differential input for channel 3 - Pins AIN3 is the negative differential input for channel 3 - -- mode 3 : two differential inputs - Pins AIN0 is the positive differential input for channel 0 - Pins AIN1 is the negative differential input for channel 0 - Pins AIN2 is the positive differential input for channel 1 - Pins AIN3 is the negative differential input for channel 1 - -For more informations see the datasheet. - - -Accessing PCF8591 via /proc interface -------------------------------------- - -! Be careful ! -The PCF8591 is plainly impossible to detect ! Stupid chip. -So every chip with adress in the interval [48..4f] is -detected as PCF8591. If you have other chips in this address -range, the workaround is to load this module after the one -for your others chips. - -On detection (i.e. insmod, modprobe et al.), directories are being -created for each detected PCF8591: - -/proc/sys/dev/sensors/pcf8591-<0>-<1>/ -where <0> is the bus the chip was detected on (e. g. i2c-0) -and <1> the chip address ([48..4f]): ./pcf8591-i2c-0-48/ - -Inside these directories, there are five files each: -ain_conf, ch0, ch1, ch2, ch3, aout_enable, aout. - -The ain_conf file is rw. Reading gives you the current analog inputs -configuration, and writing configure the analog inputs. It must be -a number between 0 and 3., other values are ignored. For the different -modes, see above in the description. - -The ch0, ch1, ch2 and ch3 files are ro. Reading gives the value -of the corresponding channel. Depending on the current analog inputs -configuration, channel ch2 and/or ch3 may are not used by the chip -and so read as 0. Values range are from 0 to 255 for single -ended inputs and -128 to +127 for differential inputs (8-bit ADC). - -The aout_enable is rw. Reading gives "1" for analog output enabled and -"0" for analog output disabled. Writing accepts "0" and "1" accordingly. - -The aout is rw. Writing a number between 0 and 255 (8-bit DAC), send -the value to the digital-to-analog converter. Note that a voltage will -only appears on AOUT pin if aout_enable equals 1. Reading returns the last -value written. - -On module initialization the chip is configured as followed : -- four single ended differential inputs -- analog output set to 0 and enabled - - -Chip Features -------------- - -Chip `pcf8591' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - ain_conf NONE NONE RW 0 - ch0 NONE NONE R 0 - ch1 NONE NONE R 0 - ch2 NONE NONE R 0 - ch3 NONE NONE R 0 - aout_enable NONE NONE RW 0 - aout NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET - ain_conf SENSORS_PCF8591_AIN_CONF ain_conf:1 - ch0 SENSORS_PCF8591_CH0 ain_ch0:1 - ch1 SENSORS_PCF8591_CH1 ain_ch1:1 - ch2 SENSORS_PCF8591_CH2 ain_ch2:1 - ch3 SENSORS_PCF8591_CH3 ain_ch3:1 - aout_enable SENSORS_PCF8591_AOUT_ENABLE aout_enable:1 - aout SENSORS_PCF8591_AOUT aout:1 diff --git a/doc/chips/saa1064 b/doc/chips/saa1064 deleted file mode 100644 index bc246eab..00000000 --- a/doc/chips/saa1064 +++ /dev/null @@ -1,81 +0,0 @@ -Kernel driver `saa1064.o' -======================== - -Status: Testing; - -Supported chips: - * Philips SAA1064 - Prefix: 'saa1064' - Addresses scanned: I2C 0x38 - 0x3b - Datasheet: Publicly available at the Philips Semiconductors website - http://www.semiconductors.philips.com/ - http://www.philipslogic.com/products/i2c/pdf/saa1064.pdf - - -Author: Sascha Volkenandt - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_saa1064: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to - contain a `saa1064' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ -The SAA1064 is a 4-digit LED driver chip for the I2C bus produced by Philips -Semiconductors. It is designed to provide a byte I2C interface to up to 4 -separate 4-digit displays (16 digits). - -This device has eight write-only registers, five are used for a control byte -and the four digit values. - -For more informations see the datasheet. - - -Accessing SAA1064 via /proc interface -------------------------------------- - -On detection (i.e. insmod, modprobe et al.), directories are being -created for each detected SAA1064: - -/proc/sys/dev/sensors/saa1064-<0>-<1>/ -where <0> is the bus the chip was detected on (e. g. i2c-0) -and <1> the chip address ([38..3b]): -./saa1064-i2c-0-38/ - -Inside these directories, there are four files each: -bright, test, disp and refresh - -The bright, test and disp files are read-write. - -Writing bright sets the output current to the LEDs connected to the -chip and thus the brightness. Range is from 0 to 7. Reading -gives you the last known value. - -Writing test sets the segment test mode (all LEDs lit regardless of -the digit values) on/off (values 0/1). Reading gives you the last -known value. - -Writing up to four values to disp sets the digits. Each value represents -one segment, while each bit represents one LED of the segment (seven bars -and one dot usually). Reading gives you the last known value. - -The refresh file is read-only. You can't read anything from it, but -reading it will trigger a refresh in case a power-loss has occurred since -the last refresh. - -On module initialization the chip is configured for segment test (test=1), -full brightness (bright=7), all digit values zeroed. - diff --git a/doc/chips/sis5595 b/doc/chips/sis5595 deleted file mode 100644 index a6f4f02b..00000000 --- a/doc/chips/sis5595 +++ /dev/null @@ -1,165 +0,0 @@ -Kernel driver `sis5595.o' -========================= - -Status: Complete and tested - -Supported chips: - * Silicon Integrated Systems Corp. SiS5595 Southbridge Hardware Monitor - Prefix: sis5595 - Addresses scanned: ISA in PCI-space encoded address - Datasheet: Publicly available at the Silicon Integrated Systems Corp. site. - - Supports following revisions: - Version PCI ID PCI Revision - 1 1039/0008 01 - 2 1039/0008 C0 - -Author: Kyösti Mälkki - - Note: The chips below contain a 0008 device which is incompatible with the - 5595. We recognize these by the presence of the listed - "blacklist" PCI ID and refuse to load. - - NOT SUPPORTED PCI ID BLACKLIST PCI ID - 540 0008 0540 - 550 0008 0550 - 5513 0008 5511 - 5581 0008 5597 - 5582 0008 5597 - 5597 0008 5597 - 5598 0008 5597/5598 - 630 0008 0630 - 645 0008 0645 - 730 0008 0730 - 735 0008 0735 - -Module Parameters ------------------ -force_addr=0xaddr Set the I/O base address. Useful for boards - that don't set the address in the BIOS. Does not do a - PCI force; the device must still be present in lspci. - Don't use this unless the driver complains that the - base address is not set. - Example: 'modprobe sis5595 force_addr=0x290' - - -Description ------------ - -The Sis5595 southbridge has integrated hardware monitor functions. -It also has an I2C bus, but this driver only supports the hardware monitor. -For the I2C bus driver see i2c-sis5595. - -The SiS5595 implements zero or one temperature sensor, two fan speed -sensors, four or five voltage sensors, and alarms. - -On the first version of the chip, there are four voltage -sensors and one temperature sensor. - -On the second version of the chip, -the temperature sensor (temp) and the fifth voltage sensor (in4) share a pin -which is configurable, but not through the driver. Sorry. -The driver senses the configuration of the pin, which was hopefully -set by the BIOS. -If the temperature function is enabled, in4 will return 0. -If the in4 function is enabled, temp will return 0. - -Temperatures are measured in degrees Celsius. An alarm is triggered once -when the max is crossed; it is also triggered -when it drops below the min value. -Measurements are guaranteed -between -55 and +125 degrees, with a resolution of 1 degree. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -Voltage sensors (also known as IN sensors) report their values in volts. -An alarm is triggered if the voltage has crossed a programmable minimum -or maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. All voltage -inputs can measure voltages between 0 and 4.08 volts, with a resolution -of 0.016 volt. - -In addition to the alarms described above, there is a BTI alarm, which gets -triggered when an external chip has crossed its limits. Usually, this is -connected to some LM75-like chip; if at least one crosses its limits, this -bit gets set. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.5 seconds since the last update). This means that you can easily -miss once-only alarms. - -The Sis5595 only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. - -Problems --------- -Some chips refuse to be enabled. We don't know why. -The driver will recognize this and print a message in dmesg. - -Chip Features -------------- - -Chip `sis5595' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in4 in4 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in4 in4 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - alarms NONE NONE R 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - in0 SENSORS_SIS5595_IN0 in0:3 - in1 SENSORS_SIS5595_IN1 in1:3 - in2 SENSORS_SIS5595_IN2 in2:3 - in3 SENSORS_SIS5595_IN3 in3:3 - in4 SENSORS_SIS5595_IN4 in3:3 - in0_min SENSORS_SIS5595_IN0_MIN in0:1 - in1_min SENSORS_SIS5595_IN1_MIN in1:1 - in2_min SENSORS_SIS5595_IN2_MIN in2:1 - in3_min SENSORS_SIS5595_IN3_MIN in3:1 - in4_min SENSORS_SIS5595_IN4_MIN in4:1 - in0_max SENSORS_SIS5595_IN0_MAX in0:2 - in1_max SENSORS_SIS5595_IN1_MAX in1:2 - in2_max SENSORS_SIS5595_IN2_MAX in2:2 - in3_max SENSORS_SIS5595_IN3_MAX in3:2 - in4_max SENSORS_SIS5595_IN4_MAX in4:2 - fan1 SENSORS_SIS5595_FAN1 fan1:2 - fan2 SENSORS_SIS5595_FAN2 fan2:2 - fan1_min SENSORS_SIS5595_FAN1_MIN fan1:1 - fan2_min SENSORS_SIS5595_FAN2_MIN fan2:1 - temp SENSORS_SIS5595_TEMP temp:3 - temp_hyst SENSORS_SIS5595_TEMP_HYST temp:2 - temp_over SENSORS_SIS5595_TEMP_OVER temp:1 - fan1_div SENSORS_SIS5595_FAN1_DIV fan_div:1 - fan2_div SENSORS_SIS5595_FAN2_DIV fan_div:2 - alarms SENSORS_SIS5595_ALARMS alarms:1 - - diff --git a/doc/chips/smartbatt b/doc/chips/smartbatt deleted file mode 100644 index 14e2b14d..00000000 --- a/doc/chips/smartbatt +++ /dev/null @@ -1,66 +0,0 @@ -Kernel driver `smartbatt.o' -========================== - -Status: Alpha - -Supported chips: - * Smart batteries - Prefix: 'smartbatt' - Address scanned: 0x0b - Datasheet: Smart Battery Data Specification Revision 1.1 - http://www.sbs-forum.org/ - -Author: M. Studebaker - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_smartbatt: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `smartbatt' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Detection ---------- - -Very poor. Just looks for the presence of some registers. - - -Uses ----- - -Provides read-only access to battery voltage, current, temperature, -charge status, time remaining, and alarms. - - -/proc entries -------------- - -Average readings are one minute rolling averages. - - alarms bitmask - charge relative charge, absolute charge (%) - i average current, instantaneous current (A) - temp temperature (deg. C) - time avg. time to empty, avg. time to full, - instantaneous time to full (min) - v max voltage, current voltage (V) - - -To do ------ - -More features. diff --git a/doc/chips/smbus-arp b/doc/chips/smbus-arp deleted file mode 100644 index e04fc0a4..00000000 --- a/doc/chips/smbus-arp +++ /dev/null @@ -1,66 +0,0 @@ -SMBUS_ARP Driver -------------- -This is a demonstration driver which provides SMBus 2.0 -ARP services. It isn't much use except for testing SMBus 2.0 -ARP and PEC support in the i2c layer. -It is NOT a normal 'chip' driver for a particular sensor device. -If you don't know what SMBus ARP is you don't need this driver. - - -Stability ---------- -Beta. - - -DETECTION -------------- -This driver requires SMBus 2.0 support in i2c-2.6.4 or higher. -If your kernel does not have i2c-2.6.4 or higher the module -will refuse to load. - -This driver will register itself on each i2c bus which -supports SMBus Block Data transactions. - - -USES ----- -The module ARPs each supported bus when it is inserted -(or after that when a i2c bus driver is inserted). -It does not periodically re-ARP, and the i2c stack does not -currently support SMBus Host Notify, so it will not detect -hot-plugged devices. - -The smbus-arp module should be inserted before any chip modules -so that it has an opportunity to assign addresses. - - -/PROC ENTRIES -------------- -There are 8 entries in /proc, 0-7. Each is a 'slot'. -If a chip has responded to ARP, it will appear in a 'slot' -as follows. See the SMBus 2.0 Specification for details. - - value function - 1 SMBus address - 2 UDID Device Capabilities - 3 UDID Version / Revision - 4 UDID Vendor ID - 5 UDID Device ID - 6 UDID Interface - 7 UDID Subsystem Vendor ID - 8 UDID Subsystem Device ID - 9 UDID Vendor Specific ID - -To reassign a device to a different address, write -that address to the slot. For example, 'echo 13 > 0' -to reassign the device in slot 0 to address 13 (0x0d). - - -TO DO ------ -lots - -Author/Maintainer ------------------ -Mark D. Studebaker (mdsxyz123@yahoo.com) - diff --git a/doc/chips/smsc47m1 b/doc/chips/smsc47m1 deleted file mode 100644 index 6c1c35ae..00000000 --- a/doc/chips/smsc47m1 +++ /dev/null @@ -1,75 +0,0 @@ -Kernel driver `smsc47m1.o' -========================== - -Status: Beta. - -Supported chips: - * SMSC LPC47B27x, LPC47M112, LPC47M10x, LPC47M13x, LPC47M14x, - LPC47M15x and LPC47M192 - Prefix: 'smsc47m1' - Addresses scanned: none, address read from Super I/O config space - Datasheets: - http://www.smsc.com/main/datasheets/47b27x.pdf - http://www.smsc.com/main/datasheets/47m10x.pdf - http://www.smsc.com/main/datasheets/47m112.pdf - http://www.smsc.com/main/tools/discontinued/47m13x.pdf - http://www.smsc.com/main/datasheets/47m14x.pdf - http://www.smsc.com/main/tools/discontinued/47m15x.pdf - http://www.smsc.com/main/datasheets/47m192.pdf - * SMSC LPC47M292 - Prefix: 'smsc47m2' - Addresses scanned: none, address read from Super I/O config space - Datasheet: Not public - * SMSC LPC47M997 - Addresses scanned: none, address read from Super I/O config space - Prefix: 'smsc47m1' - Datasheet: none - -Authors: Mark D. Studebaker - With assistance from Bruce Allen and his - fan.c program: http://www.lsc-group.phys.uwm.edu/%7Eballen/driver/ - -Module Parameters ------------------ - -force_addr=0xaddr Set the I/O base address. Useful for boards - that don't set the address in the BIOS. - Don't use this unless the driver complains that the - base address is not set. - Example: 'modprobe smsc47m1 force_addr=0x680' - - -Description ------------ - -The Standard Microsystems Corporation (SMSC) 47M1xx Super I/O chips -contain monitoring and PWM control circuitry for two fans. - -The LPC47M15x, LPC47M192 and LPC47M292 chips contain a full 'hardware -monitoring block' in addition to the fan monitoring and control. The -hardware monitoring block is not supported by the driver. - -No documentation is available for the 47M997, but it has the same device -ID as the 47M15x and 47M192 chips and seems to be compatible therewith. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -PWM values are from 0 to 255. The first value in the /proc entry is -the pwm value; the second is the enable (0 or 1). - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.5 seconds since the last update). This means that you can easily -miss once-only alarms. - - -********************** -The lm_sensors project gratefully acknowledges the support of -Intel in the development of this driver. diff --git a/doc/chips/thmc50 b/doc/chips/thmc50 deleted file mode 100644 index 33205c53..00000000 --- a/doc/chips/thmc50 +++ /dev/null @@ -1,96 +0,0 @@ -Kernel driver `thmc50.o' -===================== - -Status: Complete and some-what tested - -Supported chips: - * Analog Devices ADM1022 - Prefix: 'adm1022' - Addresses scanned: I2C 0x2D - 0x2F - Datasheet: Publicly available at the Analog Devices website - * Texas Instruments THMC50 - Prefix: 'thmc50' - Addresses scanned: I2C 0x2D - 0x2F - Datasheet: Publicly available at the Texas Instruments' website - -Authors: Frodo Looijaard and - Philip Edelbrock - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_thmc50: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `thmc50' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally - - -Description ------------ - -The THMC50 implements: an internal temperature sensor, support for an -external diode-type temperature sensor (compatible w/ the diode sensor inside -many processors), and a controllable fan/analog_out DAC. For the temperature -sensors, limits can be set through the appropriate Overtemperature Shutdown -register and Hysteresis register. Each value can be set and read to half-degree -accuracy. An alarm is issued (usually to a connected LM78) when the -temperature gets higher then the Overtemperature Shutdown value; it stays on -until the temperature falls below the Hysteresis value. All temperatures are in -degrees Celsius, and are guaranteed within a range of -55 to +125 degrees. - -The THMC50 only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. - -The THMC50 is usually used in combination with LM78-like chips, to measure -the temperature of the processor(s). - - -Driver Features ---------------- - -These are the files which are provided by the driver (ro=read-only, -rw=read and writeable): - -temp1 (internal) -- Three fields: [temp-os,rw] [temp-hyst,rw] [temp,ro] -temp2 (remote) -- Three fields: [temp-os,rw] [temp-hyst,rw] [temp,ro] - -temp-os, temp-hyst, and temp are whole degree integers representing degrees -Celsius. - -analog_out -- One field: [output-value,rw] - -output-value is a number from 0 to 255 representing the voltage output -provided by the DAC from 0 to 2.5, respectively. Note: the max *current* -supplied is actually quite low. Some type of current amplification is needed -in order to control a fan or other current demanding device (see the -datasheet for more info). - -die_code -- One field: [die-code,ro] - -die-code is an integer representation of the die_code byte register. -According to the docs, the high nibble is the die version, and the lower -nibble is the stepping. (Don't ask me why or what this means! ;') - -inter -- One field: [interrupts,rw] - -interrupts is an integer representation of the interrupts byte. See the data -sheet for what bits mean what. - -inter_mask -- One field: [inter-mask,rw] - -inter-mask is an integer repressentation of the interrupt mask which is a -determination of which conditions can cause the /INT pin on the chip to -become asserted. - - - diff --git a/doc/chips/via686a b/doc/chips/via686a deleted file mode 100644 index 6db475fa..00000000 --- a/doc/chips/via686a +++ /dev/null @@ -1,155 +0,0 @@ -Kernel driver `via686a.o' -========================= - -Status: Stable. - -Supported chips: - * Via VT82C686A, VT82C686B Southbridge Integrated Hardware Monitor - Prefix: 'via686a' - Addresses scanned: ISA in PCI-space encoded address - Datasheet: On request through web form - (http://www.via.com.tw/en/support/datasheets/) - -Authors: Kyösti Mälkki , - Mark D. Studebaker - Bob Dougherty - (Some conversion-factor data were contributed by - Jonathan Teh Soon Yew - and Alex van Kaam .) - -Module Parameters ------------------ - -force_addr=0xaddr Set the I/O base address. Useful for boards that - don't set the address in the BIOS. Look for a BIOS - upgrade before resorting to this. Does not do a - PCI force; the via686a must still be present in lspci. - Don't use this unless the driver complains that the - base address is not set. - Example: 'modprobe via686a force_addr=0x6000' - - -Description ------------ - -The driver does not distinguish between the chips and reports -all as a 686A. - -The Via 686a southbridge has integrated hardware monitor functionality. -It also has an I2C bus, but this driver only supports the hardware monitor. -For the I2C bus driver, see ../busses/i2c-viapro. - -The Via 686a implements three temperature sensors, two fan rotation speed -sensors, five voltage sensors and alarms. - -Temperatures are measured in degrees Celsius. An alarm is triggered once -when the Overtemperature Shutdown limit is crossed; it is triggered again -as soon as it drops below the hysteresis value. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -Voltage sensors (also known as IN sensors) report their values in volts. -An alarm is triggered if the voltage has crossed a programmable minimum -or maximum limit. Voltages are internally scalled, so each voltage channel -has a different resolution and range. - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.5 seconds since the last update). This means that you can easily -miss once-only alarms. - -The driver only updates its values each 1.5 seconds; reading it more often -will do no harm, but will return 'old' values. - - -Known Issues ------------- - -This driver handles sensors integrated in some VIA south bridges. It is -possible that a motherboard maker used a VT82C686A/B chip as part of a -product design but was not interested in its hardware monitoring features, -in which case the sensor inputs will not be wired. This is the case of -the Asus K7V, A7V and A7V133 motherboards, to name only a few of them. -So, if you need the force_addr parameter, and end up with values which -don't seem to make any sense, don't look any further: your chip is simply -not wired for hardware monitoring. - - -Chip Features -------------- - -Chip `via686a' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in3 in3 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in3 in3 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan1_min fan1 fan1 RW 0 - fan2_min fan2 fan2 RW 0 - temp NONE NONE R 1 - temp_hyst temp temp RW 1 - temp_over temp temp RW 1 - temp2 NONE NONE R 1 - temp2_hyst temp temp RW 1 - temp2_over temp temp RW 1 - temp3 NONE NONE R 1 - temp3_hyst temp temp RW 1 - temp3_over temp temp RW 1 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - alarms NONE NONE R 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - in0 SENSORS_VIA686A_IN0 in0:3 - in1 SENSORS_VIA686A_IN1 in1:3 - in2 SENSORS_VIA686A_IN2 in2:3 - in3 SENSORS_VIA686A_IN3 in3:3 - in4 SENSORS_VIA686A_IN4 in4:3 - in0_min SENSORS_VIA686A_IN0_MIN in0:1 - in1_min SENSORS_VIA686A_IN1_MIN in1:1 - in2_min SENSORS_VIA686A_IN2_MIN in2:1 - in3_min SENSORS_VIA686A_IN3_MIN in3:1 - in4_min SENSORS_VIA686A_IN4_MIN in4:1 - in0_max SENSORS_VIA686A_IN0_MAX in0:2 - in1_max SENSORS_VIA686A_IN1_MAX in1:2 - in2_max SENSORS_VIA686A_IN2_MAX in2:2 - in3_max SENSORS_VIA686A_IN3_MAX in3:2 - in4_max SENSORS_VIA686A_IN4_MAX in4:2 - fan1 SENSORS_VIA686A_FAN1 fan1:2 - fan2 SENSORS_VIA686A_FAN2 fan2:2 - fan1_min SENSORS_VIA686A_FAN1_MIN fan1:1 - fan2_min SENSORS_VIA686A_FAN2_MIN fan2:1 - temp SENSORS_VIA686A_TEMP temp:3 - temp_hyst SENSORS_VIA686A_TEMP_HYST temp:2 - temp_over SENSORS_VIA686A_TEMP_OVER temp:1 - temp2 SENSORS_VIA686A_TEMP2 temp2:3 - temp2_hyst SENSORS_VIA686A_TEMP2_HYST temp2:2 - temp2_over SENSORS_VIA686A_TEMP2_OVER temp2:1 - temp3 SENSORS_VIA686A_TEMP3 temp3:3 - temp3_hyst SENSORS_VIA686A_TEMP3_HYST temp3:2 - temp3_over SENSORS_VIA686A_TEMP3_OVER temp3:1 - fan1_div SENSORS_VIA686A_FAN1_DIV fan_div:1 - fan2_div SENSORS_VIA686A_FAN2_DIV fan_div:2 - alarms SENSORS_VIA686A_ALARMS alarms:1 - - diff --git a/doc/chips/vt1211 b/doc/chips/vt1211 deleted file mode 100644 index a6156687..00000000 --- a/doc/chips/vt1211 +++ /dev/null @@ -1,70 +0,0 @@ -Kernel driver `vt1211.o' -========================= - -Status: Beta. - -Supported chips: - * Via VT1211 Super I/O Controller - Addresses scanned: none, address read from Super I/O config space - -Authors: Mark D. Studebaker - - -Module Parameters ------------------ - -force_addr=0xaddr Set the I/O base address. Useful for boards - that don't set the address in the BIOS. - Don't use this unless the driver complains that the - base address is not set. - Example: 'modprobe vt1211 force_addr=0x680' - - -Description ------------ - -The Via VT1211 Super I/O chip -contains voltage/temperature monitoring and -PWM control circuitry for two fans. - -We define the sensors as follows. Somewhat convoluted to minimize -changes from via686a. - - Sensor Voltage Mode Temp Mode uch_config bit - -------- ------------ --------- -------------- - Reading 1 temp3 - Reading 3 temp1 - UCH1/Reading2 in0 temp2 0x04 (4) - UCH2 in1 temp4 0x08 (8) - UCH3 in2 temp5 0x10 (16) - UCH4 in3 temp6 0x20 (32) - UCH5 in4 temp7 0x40 (64) - 3.3V in5 - -As noted above, 5 of the sensors are "universal channels" and can -be set for either voltage or temperature. -Set the uch_config bit (in /proc) to 0 for voltage and 1 for temperature. -Voltages will read 0 if set for temperature. -Temperatures will read a really low number if set for voltage. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -PWM values are from 0 to 255. The first value in the /proc entry is -the pwm value; the second is the enable (0 or 1). - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.5 seconds since the last update). This means that you can easily -miss once-only alarms. - - -********************** -The lm_sensors project gratefully acknowledges the support of -Via in the development of this driver. diff --git a/doc/chips/vt8231 b/doc/chips/vt8231 deleted file mode 100644 index fdf7c989..00000000 --- a/doc/chips/vt8231 +++ /dev/null @@ -1,184 +0,0 @@ -Kernel driver `vt8231.o' -======================== - -Status: Beta - -Supported chips: - * VIA VT8231 South Bridge - Prefix: 'vt8231' - Addresses scanned: none, address read from PCI space - -Author: Mark D. Studebaker - -License: GPL - - -Module Parameters ------------------ - -* force_addr: int - Initialize the base address of the sensors -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_vt8231: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `vt8231' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -The VIA VT8231 South Bridge contains voltage/temperature monitoring and -PWM control circuitry for two fans. - -We define the sensors as follows. - - Sensor Voltage Mode Temp Mode uch_config bit - ------ ------------ --------- -------------- - Reading 1 temp1 - UCH1 in0 temp2 0x04 (4) - UCH2 in1 temp3 0x08 (8) - UCH3 in2 temp4 0x10 (16) - UCH4 in3 temp5 0x20 (32) - UCH5 in4 temp6 0x40 (64) - 3.3V in5 - -As noted above, 5 of the sensors are "universal channels" and can -be set for either voltage or temperature. -Set the uch_config bit (in /proc) to 0 for voltage and 1 for temperature. -Voltages will read 0 if set for temperature. -Temperatures will read a really low number if set for voltage. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -PWM values are from 0 to 255. The first value in the /proc entry is -the pwm value; the second is the enable (0 or 1). - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.5 seconds since the last update). This means that you can easily -miss once-only alarms. - - -Chip Features -------------- - -Chip 'vt8231' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -in0 - - R- 2 -in1 - - R- 2 -in2 - - R- 2 -in3 - - R- 2 -in4 - - R- 2 -in5 - - R- 2 -in0_min in0 in0 RW 2 -in1_min in1 in1 RW 2 -in2_min in2 in2 RW 2 -in3_min in3 in3 RW 2 -in4_min in4 in4 RW 2 -in5_min in5 in5 RW 2 -in0_max in0 in0 RW 2 -in1_max in1 in1 RW 2 -in2_max in2 in2 RW 2 -in3_max in3 in3 RW 2 -in4_max in4 in4 RW 2 -in5_max in5 in5 RW 2 -fan1 - - R- 0 -fan2 - - R- 0 -fan1_min fan1 fan1 RW 0 -fan2_min fan2 fan2 RW 0 -temp1 - - R- 1 -temp1_hyst temp1 temp1 RW 1 -temp1_over temp1 temp1 RW 1 -temp2 - - R- 2 -temp2_hyst temp2 temp2 RW 2 -temp2_over temp2 temp2 RW 2 -temp3 - - R- 2 -temp3_hyst temp3 temp3 RW 2 -temp3_over temp3 temp3 RW 2 -temp4 - - R- 2 -temp4_hyst temp4 temp4 RW 2 -temp4_over temp4 temp4 RW 2 -temp5 - - R- 2 -temp5_hyst temp5 temp5 RW 2 -temp5_over temp5 temp5 RW 2 -temp6 - - R- 2 -temp6_hyst temp6 temp6 RW 2 -temp6_over temp6 temp6 RW 2 -fan1_div fan1 - RW 0 -fan2_div fan2 - RW 0 -alarms - - R- 0 -vid - - R- 3 -vrm - - RW 1 -config - - R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -in0 SENSORS_VT8231_IN0 in0:3 -in1 SENSORS_VT8231_IN1 in1:3 -in2 SENSORS_VT8231_IN2 in2:3 -in3 SENSORS_VT8231_IN3 in3:3 -in4 SENSORS_VT8231_IN4 in4:3 -in5 SENSORS_VT8231_IN5 in5:3 -in0_min SENSORS_VT8231_IN0_MIN in0:1 -in1_min SENSORS_VT8231_IN1_MIN in1:1 -in2_min SENSORS_VT8231_IN2_MIN in2:1 -in3_min SENSORS_VT8231_IN3_MIN in3:1 -in4_min SENSORS_VT8231_IN4_MIN in4:1 -in5_min SENSORS_VT8231_IN5_MIN in5:1 -in0_max SENSORS_VT8231_IN0_MAX in0:2 -in1_max SENSORS_VT8231_IN1_MAX in1:2 -in2_max SENSORS_VT8231_IN2_MAX in2:2 -in3_max SENSORS_VT8231_IN3_MAX in3:2 -in4_max SENSORS_VT8231_IN4_MAX in4:2 -in5_max SENSORS_VT8231_IN5_MAX in5:2 -fan1 SENSORS_VT8231_FAN1 fan1:2 -fan2 SENSORS_VT8231_FAN2 fan2:2 -fan1_min SENSORS_VT8231_FAN1_MIN fan1:1 -fan2_min SENSORS_VT8231_FAN2_MIN fan2:1 -temp1 SENSORS_VT8231_TEMP temp1:3 -temp1_hyst SENSORS_VT8231_TEMP_HYST temp1:2 -temp1_over SENSORS_VT8231_TEMP_OVER temp1:1 -temp2 SENSORS_VT8231_TEMP2 temp2:3 -temp2_hyst SENSORS_VT8231_TEMP2_HYST temp2:2 -temp2_over SENSORS_VT8231_TEMP2_OVER temp2:1 -temp3 SENSORS_VT8231_TEMP3 temp3:3 -temp3_hyst SENSORS_VT8231_TEMP3_HYST temp3:2 -temp3_over SENSORS_VT8231_TEMP3_OVER temp3:1 -temp4 SENSORS_VT8231_TEMP4 temp4:3 -temp4_hyst SENSORS_VT8231_TEMP4_HYST temp4:2 -temp4_over SENSORS_VT8231_TEMP4_OVER temp4:1 -temp5 SENSORS_VT8231_TEMP5 temp5:3 -temp5_hyst SENSORS_VT8231_TEMP5_HYST temp5:2 -temp5_over SENSORS_VT8231_TEMP5_OVER temp5:1 -temp6 SENSORS_VT8231_TEMP6 temp6:3 -temp6_hyst SENSORS_VT8231_TEMP6_HYST temp6:2 -temp6_over SENSORS_VT8231_TEMP6_OVER temp6:1 -fan1_div SENSORS_VT8231_FAN1_DIV fan_div:1 -fan2_div SENSORS_VT8231_FAN2_DIV fan_div:2 -alarms SENSORS_VT8231_ALARMS alarms:1 -vid SENSORS_VT8231_VID vid:1 -vrm SENSORS_VT8231_VRM vrm:1 -config SENSORS_VT8231_UCH uch_config:1 - - -Notes ------ - -The lm_sensors project gratefully acknowledges the support of VIA in the -development of this driver. diff --git a/doc/chips/w83627hf b/doc/chips/w83627hf deleted file mode 100644 index f9836f5d..00000000 --- a/doc/chips/w83627hf +++ /dev/null @@ -1,103 +0,0 @@ -Kernel driver `w83627hf.o' -========================= - -Status: Beta. - -Supported chips: - * Winbond W83627HF (ISA accesses ONLY) - Prefix: 'w83627hf' - Addresses scanned: ISA address retrieved from Super I/O registers - Datasheet: http://www.winbond.com/PDF/sheet/w83627hf.pdf - * Winbond W83627THF - Prefix: 'w83627thf' - Addresses scanned: ISA address retrieved from Super I/O registers - Datasheet: http://www.winbond.com/PDF/sheet/w83627thf.pdf - * Winbond W83697HF - Prefix: 'w83697hf' - Addresses scanned: ISA address retrieved from Super I/O registers - Datasheet: http://www.winbond.com/PDF/sheet/w83697hf.pdf - * Winbond W83637HF - Prefix: 'w83637hf' - Addresses scanned: ISA address retrieved from Super I/O registers - Datasheet: http://www.winbond.com/PDF/sheet/w83637hf.pdf - * Winbond W83687THF - Prefix: 'w83687thf' - Addresses scanned: ISA address retrieved from Super I/O registers - Datasheet: Provided by Winbond on request - -Authors: Frodo Looijaard , Philip Edelbrock , - and Mark Studebaker - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_addr: int - Initialize the ISA address of the sensors -* force_i2c: int - Initialize the I2C address of the sensors -* force_w83627hf: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `w83627hf' chip -* force_w83627thf: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `w83627thf' chip -* force_w83697hf: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `w83697hf' chip -* force_w83637hf: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `w83637hf' chip -* force_w83687thf: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `w83687thf' chip -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* init=[0,1] (default 1) - Use 'init=0' to bypass initializing the chip. - Try this if your computer crashes when you load the module. - - -Description ------------ - -This driver implements support for ISA accesses *only* for -the Winbond W83627HF, W83627THF, W83697HF, W83637HF and W83687THF -Super I/O chips. We will refer to them collectively as Winbond chips. - -This driver supports ISA accesses, which should be more reliable -than i2c accesses. Also, for Tyan boards which contain both a -Super I/O chip and a second i2c-only Winbond chip (often a W83782D), -using this driver will avoid i2c address conflicts and complex -initialization that were required in the w83781d driver -(lm_sensors releases 2.7.0 and earlier). - -If you really want i2c accesses for these Super I/O chips, -use the w83781d driver. However this is not the preferred method -now that this ISA driver has been developed. - -The w83627_HF_ uses pins 110-106 as VID0-VID4. The w83627_THF_ uses the -same pins as GPIO[0:4]. Technically, the w83627_THF_ does not support a -VID reading. However the two chips have the identical 128 pin package. So, -it is possible or even likely for a w83627thf to have the VID signals routed -to these pins despite their not being labeled for that purpose. Therefore, -the w83627thf driver interprets these as VID. If the VID on your board -doesn't work, first see doc/vid. If that still doesn't help, you may just -ignore the bogus VID reading with no harm done. - -For further information on this driver, /proc values, etc. -see the w83781d driver documentation. - - -Author/Maintainer ------------------ -Mark D. Studebaker (mdsxyz123@yahoo.com). -Derived from the w83781d driver. diff --git a/doc/chips/w83781d b/doc/chips/w83781d deleted file mode 100644 index d1629186..00000000 --- a/doc/chips/w83781d +++ /dev/null @@ -1,799 +0,0 @@ -Kernel driver `w83781d.o' -========================= - -Status: W83781D support is complete and well-tested. - W83782D support is complete and well-tested. - W83783S support is complete but has not been well-tested. - W83791D support is BETA. - W83627HF support is complete but has not been well-tested. - AS99127F support is BETA and has known problems due to lack of a - chip datasheet. SEE BELOW. - -Supported chips: - * Winbond W83781D - Prefix: 'w83781d' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) - Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83781d.pdf - * Winbond W83782D - Prefix: 'w83782d' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) - Datasheet: http://www.winbond.com/PDF/sheet/w83782d.pdf - * Winbond W83783S - Prefix: 'w83783s' - Addresses scanned: I2C 0x2d - Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83783s.pdf - * Winbond W83791D - Prefix: 'w83791d' - Addresses scanned: I2C 0x2c - 0x2f - Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83791d.pdf - * Winbond W83627HF - Prefix: 'w83627hf' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) - Datasheet: http://www.winbond.com/PDF/sheet/w83627hf.pdf - * Asus AS99127F - Prefix: 'as99127f' - Addresses scanned: I2C 0x28 - 0x2f - Datasheet: Unavailable from Asus - - - -Authors: Frodo Looijaard , Philip Edelbrock , - and Mark Studebaker - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_w83781d: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `w83781d' chip -* force_w83782d: - Ditto -* force_w83783s: - Ditto -* force_w83791d: - Ditto -* force_w83627hf: - Ditto -* force_as99127f: - Ditto -* force_subclients=bus,caddr,saddr,saddr - This is used to force the i2c addresses for subclients of - a certain chip. Typical usage is `force_subclients=0,0x2d,0x4a,0x4b' - to force the subclients of chip 0x2d on bus 0 to i2c addresses - 0x4a and 0x4b. - This parameter is useful for certain Tyan boards. -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* init=[0,1] (default 1) - Use 'init=0' to bypass initializing the chip. - Try this if your computer crashes when you load the module. - - -Description ------------ - -This driver implements support for the Winbond W83781D, W83782D, -W83783S, W83791D, W83627HF and W83698HF chips, and the Asus AS99127F chips. -We will refer to them collectively as W8378* chips. - -There is quite some difference between these chips, but they are similar -enough that it was sensible to put them together in one driver. -The W83627HF chip is assumed to be identical to the ISA W83782D. -The Asus chips are similar to an I2C-only W83782D. - -Detection of these chips can sometimes be foiled because they can be in -an internal state that allows no clean access. If you know the address -of the chip, use a 'force' parameter; this will put them into a more -well-behaved state first. - -The W8378* implements temperature sensors (three on the W83781D and W83782D, -two on the W83783S), three fan rotation speed sensors, voltage sensors -(seven on the W83781D, nine on the W83782D and six on the W83783S), VID -lines, alarms with beep warnings, and some miscellaneous stuff. - -Temperatures are measured in degrees Celsius. There is always one main -temperature sensor, and one (W83783S) or two (W83781D and W83782D) other -sensors. An alarm is triggered for the main sensor once when the -Overtemperature Shutdown limit is crossed; it is triggered again as soon as -it drops below the Hysteresis value. A more useful behaviour -can be found by setting the Hysteresis value to +127 degrees Celsius; in -this case, alarms are issued during all the time when the actual temperature -is above the Overtemperature Shutdown value. The driver sets the -hysteresis value for temp1 to 127 at initialization. - -For the other temperature sensor(s), an -alarm is triggered when the temperature gets higher then the Overtemperature -Shutdown value; it stays on until the temperature falls below the Hysteresis -value. But on the W83781D, there is only one alarm that functions for both -other sensors! Temperatures are guaranteed within a range of -55 to +125 -degrees. The main temperature sensors has a resolution of 1 degree; the other -sensor(s) of 0.5 degree. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8 for the -W83781D; 1, 2, 4, 8, 16, 32, 64 or 128 for the others) to give -the readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. - -Voltage sensors (also known as IN sensors) report their values in volts. -An alarm is triggered if the voltage has crossed a programmable minimum -or maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. All voltage -inputs can measure voltages between 0 and 4.08 volts, with a resolution -of 0.016 volt. - -The VID lines encode the core voltage value: the voltage level your processor -should work with. This is hardcoded by the mainboard and/or processor itself. -It is a value in volts. When it is unconnected, you will often find the -value 3.50 V here. - -The W83782D and W83783S temperature conversion machine understands about -several kinds of temperature probes. You can program the so-called -beta value in the sensor files. '1' is the PII/Celeron diode, '2' is the -TN3904 transistor, and 3435 the default thermistor value. Other values -are (not yet) supported. You can program your own values through the -rt interface, but this is not very useful, because these tables are -under NDA. - -In addition to the alarms described above, there is a CHAS alarm on the -chips which triggers if your computer case is open. - -When an alarm goes off, you can be warned by a beeping signal through -your computer speaker. It is possible to enable all beeping globally, -or only the beeping for some alarms. - -Individual alarm and beep bits: - -0x000001: in0 -0x000002: in1 -0x000004: in2 -0x000008: in3 -0x000010: temp1 -0x000020: temp2 (+temp3 on W83781D) -0x000040: fan1 -0x000080: fan2 -0x000100: in4 -0x000200: in5 -0x000400: in6 -0x000800: fan3 -0x001000: chassis -0x002000: temp3 (W83782D and W83627HF only) -0x010000: in7 (W83782D and W83627HF only) -0x020000: in8 (W83782D and W83627HF only) - -If an alarm triggers, it will remain triggered until the hardware register -is read at least once. This means that the cause for the alarm may -already have disappeared! Note that in the current implementation, all -hardware registers are read whenever any data is read (unless it is less -than 1.5 seconds since the last update). This means that you can easily -miss once-only alarms. - -The chips only update values each 1.5 seconds; reading them more often -will do no harm, but will return 'old' values. - - -AS99127F PROBLEMS ------------------ -The as99127f support was developed without the benefit of a datasheet. -In most cases it is treated as a w83781d (although revision 2 of the -AS9917F looks more like a w83782d). -This support will be BETA until a datasheet is released. -One user has reported problems with fans stopping -occasionally. - -Note that the individual beep bits are inverted from the other chips. -The driver now takes care of this so that user-space applications -don't have to know about it. - -Known problems: - - Problems with diode/thermistor settings (supported?) - - One user reports fans stopping under high server load. - - Revision 2 seems to have 2 PWM registers but we don't know - how to handle them. More details below. - -These will not be fixed unless we get a datasheet. -If you have problems, please lobby Asus to release a datasheet. -Unfortunately several others have without success. -Please do not send mail to us asking for better as99127f support. -We have done the best we can without a datasheet. -Please do not send mail to the author or the sensors group asking for -a datasheet or ideas on how to convince Asus. We can't help. - - -Chip Features -------------- - -Chip `w83781d' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in5 NONE NONE R 2 - in6 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in4 in4 RW 2 - in5_min in5 in5 RW 2 - in6_min in6 in6 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in4 in4 RW 2 - in5_max in5 in5 RW 2 - in6_max in6 in6 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan1_min fan1 NONE RW 0 - fan2_min fan2 NONE RW 0 - fan3_min fan3 NONE RW 0 - temp1 NONE NONE R 1 - temp1_hyst temp1 temp1 RW 1 - temp1_over temp1 temp1 RW 1 - temp2 NONE NONE R 1 - temp2_hyst temp2 temp2 RW 1 - temp2_over temp2 temp2 RW 1 - temp3 NONE NONE R 1 - temp3_hyst temp3 temp3 RW 1 - temp3_over temp3 temp3 RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - fan3_div fan3 NONE R 0 - alarms NONE NONE R 0 - beep_enable alarms NONE RW 0 - beeps alarms alarms RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - in0 SENSORS_W83781D_IN0 in0:3 - in1 SENSORS_W83781D_IN1 in1:3 - in2 SENSORS_W83781D_IN2 in2:3 - in3 SENSORS_W83781D_IN3 in3:3 - in4 SENSORS_W83781D_IN4 in4:3 - in5 SENSORS_W83781D_IN5 in5:3 - in6 SENSORS_W83781D_IN6 in6:3 - in0_min SENSORS_W83781D_IN0_MIN in0:1 - in1_min SENSORS_W83781D_IN1_MIN in1:1 - in2_min SENSORS_W83781D_IN2_MIN in2:1 - in3_min SENSORS_W83781D_IN3_MIN in3:1 - in4_min SENSORS_W83781D_IN4_MIN in4:1 - in5_min SENSORS_W83781D_IN5_MIN in5:1 - in6_min SENSORS_W83781D_IN6_MIN in6:1 - in0_max SENSORS_W83781D_IN0_MAX in0:2 - in1_max SENSORS_W83781D_IN1_MAX in1:2 - in2_max SENSORS_W83781D_IN2_MAX in2:2 - in3_max SENSORS_W83781D_IN3_MAX in3:2 - in4_max SENSORS_W83781D_IN4_MAX in4:2 - in5_max SENSORS_W83781D_IN5_MAX in5:2 - in6_max SENSORS_W83781D_IN6_MAX in6:2 - fan1 SENSORS_W83781D_FAN1 fan1:2 - fan2 SENSORS_W83781D_FAN2 fan2:2 - fan3 SENSORS_W83781D_FAN3 fan3:2 - fan1_min SENSORS_W83781D_FAN1_MIN fan1:1 - fan2_min SENSORS_W83781D_FAN2_MIN fan2:1 - fan3_min SENSORS_W83781D_FAN3_MIN fan3:1 - temp1 SENSORS_W83781D_TEMP1 temp1:3 - temp1_hyst SENSORS_W83781D_TEMP1_HYST temp1:2 - temp1_over SENSORS_W83781D_TEMP1_OVER temp1:1 - temp2 SENSORS_W83781D_TEMP2 temp2:3 - temp2_hyst SENSORS_W83781D_TEMP2_HYST temp2:2 - temp2_over SENSORS_W83781D_TEMP2_OVER temp2:1 - temp3 SENSORS_W83781D_TEMP3 temp3:3 - temp3_hyst SENSORS_W83781D_TEMP3_HYST temp3:2 - temp3_over SENSORS_W83781D_TEMP3_OVER temp3:1 - vid SENSORS_W83781D_VID vid:1 - fan1_div SENSORS_W83781D_FAN1_DIV fan_div:1 - fan2_div SENSORS_W83781D_FAN2_DIV fan_div:2 - fan3_div SENSORS_W83781D_FAN3_DIV fan_div:3 - alarms SENSORS_W83781D_ALARMS alarms:1 - beep_enable SENSORS_W83781D_BEEP_ENABLE beep:1 - beeps SENSORS_W83781D_BEEPS beep:2 - - -Chip `w83782d' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in5 NONE NONE R 2 - in6 NONE NONE R 2 - in7 NONE NONE R 2 - in8 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in4 in4 RW 2 - in5_min in5 in5 RW 2 - in6_min in6 in6 RW 2 - in7_min in7 in7 RW 2 - in8_min in8 in8 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in4 in4 RW 2 - in5_max in5 in5 RW 2 - in6_max in6 in6 RW 2 - in7_max in7 in7 RW 2 - in8_max in8 in8 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan1_min fan1 NONE RW 0 - fan2_min fan2 NONE RW 0 - fan3_min fan3 NONE RW 0 - temp1 NONE NONE R 1 - temp1_hyst temp1 temp1 RW 1 - temp1_over temp1 temp1 RW 1 - temp2 NONE NONE R 1 - temp2_hyst temp2 temp2 RW 1 - temp2_over temp2 temp2 RW 1 - temp3 NONE NONE R 1 - temp3_hyst temp3 temp3 RW 1 - temp3_over temp3 temp3 RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - fan3_div fan3 NONE R 0 - alarms NONE NONE R 0 - beep_enable alarms NONE RW 0 - beeps alarms alarms RW 0 - sensor1 NONE NONE RW 0 - sensor2 NONE NONE RW 0 - sensor3 NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - in0 SENSORS_W83782D_IN0 in0:3 - in1 SENSORS_W83782D_IN1 in1:3 - in2 SENSORS_W83782D_IN2 in2:3 - in3 SENSORS_W83782D_IN3 in3:3 - in4 SENSORS_W83782D_IN4 in4:3 - in5 SENSORS_W83782D_IN5 in5:3 - in6 SENSORS_W83782D_IN6 in6:3 - in7 SENSORS_W83782D_IN7 in7:3 - in8 SENSORS_W83782D_IN8 in8:3 - in0_min SENSORS_W83782D_IN0_MIN in0:1 - in1_min SENSORS_W83782D_IN1_MIN in1:1 - in2_min SENSORS_W83782D_IN2_MIN in2:1 - in3_min SENSORS_W83782D_IN3_MIN in3:1 - in4_min SENSORS_W83782D_IN4_MIN in4:1 - in5_min SENSORS_W83782D_IN5_MIN in5:1 - in6_min SENSORS_W83782D_IN6_MIN in6:1 - in7_min SENSORS_W83782D_IN7_MIN in7:1 - in8_min SENSORS_W83782D_IN8_MIN in8:1 - in0_max SENSORS_W83782D_IN0_MAX in0:2 - in1_max SENSORS_W83782D_IN1_MAX in1:2 - in2_max SENSORS_W83782D_IN2_MAX in2:2 - in3_max SENSORS_W83782D_IN3_MAX in3:2 - in4_max SENSORS_W83782D_IN4_MAX in4:2 - in5_max SENSORS_W83782D_IN5_MAX in5:2 - in6_max SENSORS_W83782D_IN6_MAX in6:2 - in7_max SENSORS_W83782D_IN7_MAX in7:2 - in8_max SENSORS_W83782D_IN8_MAX in8:2 - fan1 SENSORS_W83782D_FAN1 fan1:2 - fan2 SENSORS_W83782D_FAN2 fan2:2 - fan3 SENSORS_W83781D_FAN3 fan3:2 - fan1_min SENSORS_W83782D_FAN1_MIN fan1:1 - fan2_min SENSORS_W83782D_FAN2_MIN fan2:1 - fan3_min SENSORS_W83781D_FAN3_MIN fan3:1 - temp1 SENSORS_W83782D_TEMP1 temp1:3 - temp1_hyst SENSORS_W83782D_TEMP1_HYST temp1:2 - temp1_over SENSORS_W83782D_TEMP1_OVER temp1:1 - temp2 SENSORS_W83782D_TEMP2 temp2:3 - temp2_hyst SENSORS_W83782D_TEMP2_HYST temp2:2 - temp2_over SENSORS_W83782D_TEMP2_OVER temp2:1 - temp3 SENSORS_W83782D_TEMP3 temp3:3 - temp3_hyst SENSORS_W83782D_TEMP3_HYST temp3:2 - temp3_over SENSORS_W83782D_TEMP3_OVER temp3:1 - vid SENSORS_W83782D_VID vid:1 - fan1_div SENSORS_W83782D_FAN1_DIV fan_div:1 - fan2_div SENSORS_W83782D_FAN2_DIV fan_div:2 - fan3_div SENSORS_W83781D_FAN3_DIV fan_div:3 - alarms SENSORS_W83782D_ALARMS alarms:1 - beep_enable SENSORS_W83782D_BEEP_ENABLE beep:1 - beeps SENSORS_W83782D_BEEPS beep:2 - sensor1 SENSORS_W83782D_SENS1 sensor1:1 - sensor2 SENSORS_W83782D_SENS2 sensor2:1 - sensor3 SENSORS_W83782D_SENS3 sensor3:1 - - -Chip `w83783s' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 2 - in1 NONE NONE R 2 - in2 NONE NONE R 2 - in3 NONE NONE R 2 - in4 NONE NONE R 2 - in5 NONE NONE R 2 - in6 NONE NONE R 2 - in0_min in0 in0 RW 2 - in1_min in1 in1 RW 2 - in2_min in2 in2 RW 2 - in3_min in3 in3 RW 2 - in4_min in4 in4 RW 2 - in5_min in5 in5 RW 2 - in6_min in6 in6 RW 2 - in0_max in0 in0 RW 2 - in1_max in1 in1 RW 2 - in2_max in2 in2 RW 2 - in3_max in3 in3 RW 2 - in4_max in4 in4 RW 2 - in5_max in5 in5 RW 2 - in6_max in6 in6 RW 2 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan1_min fan1 NONE RW 0 - fan2_min fan2 NONE RW 0 - fan3_min fan3 NONE RW 0 - temp1 NONE NONE R 1 - temp1_hyst temp1 temp1 RW 1 - temp1_over temp1 temp1 RW 1 - temp2 NONE NONE R 1 - temp2_hyst temp2 temp2 RW 1 - temp2_over temp2 temp2 RW 1 - vid NONE NONE R 2 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - fan3_div fan3 NONE R 0 - alarms NONE NONE R 0 - beep_enable alarms NONE RW 0 - beeps alarms alarms RW 0 - sensor1 NONE NONE RW 0 - sensor2 NONE NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - in0 SENSORS_W83783S_IN0 in0:3 - in1 SENSORS_W83783S_IN1 in1:3 - in2 SENSORS_W83783S_IN2 in2:3 - in3 SENSORS_W83783S_IN3 in3:3 - in4 SENSORS_W83783S_IN4 in4:3 - in5 SENSORS_W83783S_IN5 in5:3 - in6 SENSORS_W83783S_IN6 in6:3 - in0_min SENSORS_W83783S_IN0_MIN in0:1 - in1_min SENSORS_W83783S_IN1_MIN in1:1 - in2_min SENSORS_W83783S_IN2_MIN in2:1 - in3_min SENSORS_W83783S_IN3_MIN in3:1 - in4_min SENSORS_W83783S_IN4_MIN in4:1 - in5_min SENSORS_W83783S_IN5_MIN in5:1 - in6_min SENSORS_W83783S_IN6_MIN in6:1 - in0_max SENSORS_W83783S_IN0_MAX in0:2 - in1_max SENSORS_W83783S_IN1_MAX in1:2 - in2_max SENSORS_W83783S_IN2_MAX in2:2 - in3_max SENSORS_W83783S_IN3_MAX in3:2 - in4_max SENSORS_W83783S_IN4_MAX in4:2 - in5_max SENSORS_W83783S_IN5_MAX in5:2 - in6_max SENSORS_W83783S_IN6_MAX in6:2 - fan1 SENSORS_W83783S_FAN1 fan1:2 - fan2 SENSORS_W83783S_FAN2 fan2:2 - fan3 SENSORS_W83783S_FAN3 fan3:2 - fan1_min SENSORS_W83783S_FAN1_MIN fan1:1 - fan2_min SENSORS_W83783S_FAN2_MIN fan2:1 - fan3_min SENSORS_W83783S_FAN3_MIN fan3:1 - temp1 SENSORS_W83783S_TEMP1 temp1:3 - temp1_hyst SENSORS_W83783S_TEMP1_HYST temp1:2 - temp1_over SENSORS_W83783S_TEMP1_OVER temp1:1 - temp2 SENSORS_W83783S_TEMP2 temp2:3 - temp2_hyst SENSORS_W83783S_TEMP2_HYST temp2:2 - temp2_over SENSORS_W83783S_TEMP2_OVER temp2:1 - vid SENSORS_W83783S_VID vid:1 - fan1_div SENSORS_W83783S_FAN1_DIV fan_div:1 - fan2_div SENSORS_W83783S_FAN2_DIV fan_div:2 - fan3_div SENSORS_W83783S_FAN3_DIV fan_div:3 - alarms SENSORS_W83783S_ALARMS alarms:1 - beep_enable SENSORS_W83783S_BEEP_ENABLE beep:1 - beeps SENSORS_W83783S_BEEPS beep:2 - sensor1 SENSORS_W83783S_SENS1 sensor1:1 - sensor2 SENSORS_W83783S_SENS2 sensor2:1 - - - -Miscellaneous documentation -=========================== - - - -/PROC ENTRIES -------------- -Varies depending on chip type. Most are identical to the lm78 entries. -See the lm78 documentation for details. - -Additional entries not in the lm78: - - pwm[1-4]: (not on w83781d nor as99127f) - Controls the speed of the fans with PWM (Pulse Width Modulation) - Valid values: - 0 - 255. 255 = max speed. - Second value is PWM enable 0/1. - - sensor[1-3]: (not on w83781d nor as99127f) - Controls the sensor type. To change to a different - sensor type, for example, do 'echo 2 > sensor1'. - Valid values: - 1: Pentium II / Celeron diode - 2: 2N3904 Transistor in a diode configuration - 3435: Thermistor with Beta = 3435. Beta is a measure - of sensitivity to temperature. - Thermistors with other Betas could in theory be supported - after correspondence with Winbond. See below. - - rt[1-3]: (w83781d only) - 32-byte tables controlling the conversion from - resistance to temperature for thermistors. - For the curious only. Writing to these entries will - probably render temperature sensing insane. - Only set at initialization; not updated every 1.5 seconds. - - - -TO DO: ------ - 782d programmable pins - - -NOTES: ------ - 783s has no in1 so that in[2-6] are compatible with the 781d/782d. - - 783s pin is programmable for -5V or temp1; defaults to -5V, - no control in driver so temp1 doesn't work. - - 782d and 783s datasheets differ on which is pwm1 and which is pwm2. - We chose to follow 782d. - - 782d and 783s pin is programmable for fan3 input or pwm2 output; - defaults to fan3 input. - If pwm2 is enabled (with echo 255 1 > pwm2), then - fan3 will report 0. - - 782d has pwm1-2 for isa, pwm1-4 for i2c. (pwm3-4 share pins with - the isa pins) - - - -Data sheet updates: ------------------- - - PWM clock registers: - - 000: master / 512 - 001: master / 1024 - 010: master / 2048 - 011: master / 4096 - 100: master / 8192 - - -Answers from Winbond tech support ---------------------------------- -> -> 1) In the W83781D data sheet section 7.2 last paragraph, it talks about -> reprogramming the R-T table if the Beta of the thermistor is not -> 3435K. The R-T table is described briefly in section 8.20. -> What formulas do I use to program a new R-T table for a given Beta? -> - We are sorry that the calculation for R-T table value is -confidential. If you have another Beta value of thermistor, we can help -to calculate the R-T table for you. But you should give us real R-T -Table which can be gotten by thermistor vendor. Therefore we will calculate -them and obtain 32-byte data, and you can fill the 32-byte data to the -register in Bank0.CR51 of W83781D. - - -> 2) In the W83782D data sheet, it mentions that pins 38, 39, and 40 are -> programmable to be either thermistor or Pentium II diode inputs. -> How do I program them for diode inputs? I can't find any register -> to program these to be diode inputs. - --> You may program Bank0 CR[5Dh] and CR[59h] registers. - - CR[5Dh] bit 1(VTIN1) bit 2(VTIN2) bit 3(VTIN3) - - thermistor 0 0 0 - diode 1 1 1 - - -(error) CR[59h] bit 4(VTIN1) bit 2(VTIN2) bit 3(VTIN3) -(right) CR[59h] bit 4(VTIN1) bit 5(VTIN2) bit 6(VTIN3) - - PII thermal diode 1 1 1 - 2N3904 diode 0 0 0 - - -Author/Maintainer ------------------ -Original 781D support: Frodo and Phil -782D/783S support added by: Mark D. Studebaker (mdsxyz123@yahoo.com) - - -Asus Clones ------------ - -We have no datasheets for the Asus clones (AS99127F and ASB100 Bach). -Here are some very useful information that were given to us by Alex Van -Kaam about how to detect these chips, and how to read their values. He -also gives advice for another Asus chipset, the Mozart-2 (which we -don't support yet). Thanks Alex! -I reworded some parts and added personal comments. - -# Detection: - -AS99127F rev.1, AS99127F rev.2 and ASB100: -- I2C address range: 0x29 - 0x2F -- If register 0x58 holds 0x31 then we have an Asus (either ASB100 or - AS99127F) -- Which one depends on register 0x4F (manufacturer ID): - 0x06 or 0x94: ASB100 - 0x12 or 0xC3: AS99127F rev.1 - 0x5C or 0xA3: AS99127F rev.2 - Note that 0x5CA3 is Winbond's ID (WEC), which let us think Asus get their - AS99127F rev.2 direct from Winbond. The other codes mean ATT and DVC, - respectively. ATT could stand for Asustek something (although it would be - very badly chosen IMHO), I don't know what DVC could stand for. Maybe - these codes simply aren't meant to be decoded that way. - -Mozart-2: -- I2C address: 0x77 -- If register 0x58 holds 0x56 or 0x10 then we have a Mozart-2 -- Of the mozart there are 3 types: - 0x58=0x56, 0x4E=0x94, 0x4F=0x36: Asus ASM58 Mozart-2 - 0x58=0x56, 0x4E=0x94, 0x4F=0x06: Asus AS2K129R Mozart-2 - 0x58=0x10, 0x4E=0x5C, 0x4F=0xA3: Asus ??? Mozart-2 - You can handle all 3 the exact same way :) - -# Temperature sensors: - -ASB100: -- sensor 1: register 0x27 -- sensor 2 & 3 are the 2 LM75's on the SMBus -- sensor 4: register 0x17 -Remark: I noticed that on Intel boards sensor 2 is used for the CPU - and 4 is ignored/stuck, on AMD boards sensor 4 is the CPU and sensor 2 is - either ignored or a socket temperature. - -AS99127F (rev.1 and 2 alike): -- sensor 1: register 0x27 -- sensor 2 & 3 are the 2 LM75's on the SMBus -Remark: Register 0x5b is suspected to be temperature type selector. Bit 1 - would control temp1, bit 3 temp2 and bit 5 temp3. - -Mozart-2: -- sensor 1: register 0x27 -- sensor 2: register 0x13 - -# Fan sensors: - -ASB100, AS99127F (rev.1 and 2 alike): -- 3 fans, identical to the W83781D - -Mozart-2: -- 2 fans only, 1350000/rpm/div -- fan 1: register 0x28, divisor on register 0xA1 (bits 4-5) -- fan 2: register 0x29, divisor on register 0xA1 (bits 6-7) - -# Voltages: - -This is where there is a difference between AS99127F rev.1 and 2. -Remark: The difference is similar to the difference between - W83781D and W83782D. - -ASB100: -in0=r(0x20)*0.016 -in1=r(0x21)*0.016 -in2=r(0x22)*0.016 -in3=r(0x23)*0.016*1.68 -in4=r(0x24)*0.016*3.8 -in5=r(0x25)*(-0.016)*3.97 -in6=r(0x26)*(-0.016)*1.666 - -AS99127F rev.1: -in0=r(0x20)*0.016 -in1=r(0x21)*0.016 -in2=r(0x22)*0.016 -in3=r(0x23)*0.016*1.68 -in4=r(0x24)*0.016*3.8 -in5=r(0x25)*(-0.016)*3.97 -in6=r(0x26)*(-0.016)*1.503 - -AS99127F rev.2: -in0=r(0x20)*0.016 -in1=r(0x21)*0.016 -in2=r(0x22)*0.016 -in3=r(0x23)*0.016*1.68 -in4=r(0x24)*0.016*3.8 -in5=(r(0x25)*0.016-3.6)*5.14+3.6 -in6=(r(0x26)*0.016-3.6)*3.14+3.6 - -Mozart-2: -in0=r(0x20)*0.016 -in1=255 -in2=r(0x22)*0.016 -in3=r(0x23)*0.016*1.68 -in4=r(0x24)*0.016*4 -in5=255 -in6=255 - - -# PWM - -Additional info about PWM on the AS99127F (may apply to other Asus -chips as well) by Jean Delvare as of 2004-04-09: - -AS99127F revision 2 seems to have two PWM registers at 0x59 and 0x5A, -and a temperature sensor type selector at 0x5B (which basically means -that they swapped registers 0x59 and 0x5B when you compare with Winbond -chips). -Revision 1 of the chip also has the temperature sensor type selector at -0x5B, but PWM registers have no effect. - -We don't know exactly how the temperature sensor type selection works. -Looks like bits 1-0 are for temp1, bits 3-2 for temp2 and bits 5-4 for -temp3, although it is possible that only the most significant bit matters -each time. So far, values other than 0 always broke the readings. - -PWM registers seem to be split in two parts: bit 7 is a mode selector, -while the other bits seem to define a value or threshold. - -When bit 7 is clear, bits 6-0 seem to hold a threshold value. If the value -is below a given limit, the fan runs at low speed. If the value is above -the limit, the fan runs at full speed. We have no clue as to what the limit -represents. Note that there seem to be some inertia in this mode, speed -changes may need some time to trigger. Also, an hysteresis mechanism is -suspected since walking through all the values increasingly and then -decreasingly led to slightly different limits. - -When bit 7 is set, bits 3-0 seem to hold a threshold value, while bits 6-4 -would not be significant. If the value is below a given limit, the fan runs -at full speed, while if it is above the limit it runs at low speed (so this -is the contrary of the other mode, in a way). Here again, we don't know -what the limit is supposed to represent. - -One remarkable thing is that the fans would only have two or three -different speeds (transitional states left apart), not a whole range as -you usually get with PWM. - -As a conclusion, you can write 0x00 or 0x8F to the PWM registers to make -fans run at low speed, and 0x7F or 0x80 to make them run at full speed. - -Please contact us if you can figure out how it is supposed to work. As -long as we don't know more, the w83781d driver doesn't handle PWM on -AS99127F chips at all. - -Additional info about PWM on the AS99127F rev.1 by Hector Martin: - -I've been fiddling around with the (in)famous 0x59 register and -found out the following values do work as a form of coarse pwm: - -0x80 - seems to turn fans off after some time(1-2 minutes)... might be -some form of auto-fan-control based on temp? hmm (Qfan? this mobo is an -old ASUS, it isn't marketed as Qfan. Maybe some beta pre-attempt at Qfan -that was dropped at the BIOS) -0x81 - off -0x82 - slightly "on-ner" than off, but my fans do not get to move. I can -hear the high-pitched PWM sound that motors give off at too-low-pwm. -0x83 - now they do move. Estimate about 70% speed or so. -0x84-0x8f - full on - -Changing the high nibble doesn't seem to do much except the high bit -(0x80) must be set for PWM to work, else the current pwm doesn't seem to -change. - -My mobo is an ASUS A7V266-E. This behaviour is similar to what I got -with speedfan under Windows, where 0-15% would be off, 15-2x% (can't -remember the exact value) would be 70% and higher would be full on. diff --git a/doc/chips/w83792d b/doc/chips/w83792d deleted file mode 100644 index 046692e8..00000000 --- a/doc/chips/w83792d +++ /dev/null @@ -1,298 +0,0 @@ -Kernel driver `w83792d.o' -========================= - -Status: W83792D support is complete and well-tested. - - -Supported chips: - * Winbond W83792D - Prefix: 'w83792d' - Addresses scanned: I2C 0x2c - 0x2f - Datasheet: http://www.winbond.com.tw/E-WINBONDHTM/partner/PDFresult.asp?Pname=1035 - -Author: Chunhao Huang -Contact: DZShen - - -Module Parameters ------------------ - -* init int - (default 1) - Use 'init=0' to bypass initializing the chip. - Try this if your computer crashes when you load the module. - -* force_subclients=bus,caddr,saddr,saddr - This is used to force the i2c addresses for subclients of - a certain chip. Example usage is `force_subclients=0,0x2f,0x4a,0x4b' - to force the subclients of chip 0x2f on bus 0 to i2c addresses - 0x4a and 0x4b. - - -Description ------------ - -This driver implements support for the Winbond W83792AD/D. - -Detection of the chip can sometimes be foiled because it can be in an -internal state that allows no clean access (Bank with ID register is not -currently selected). If you know the address of the chip, use a 'force' -parameter; this will put it into a more well-behaved state first. - -The driver implements three temperature sensors, seven fan rotation speed -sensors, nine voltage sensors, and two automatic fan regulation -strategies called: Smart Fan I (Thermal Cruise mode) and Smart Fan II. -Automatic fan control mode is possible only for fan1-fan3. Fan4-fan7 can run -synchronized with selected fan (fan1-fan3). This functionality and manual PWM -control for fan4-fan7 is not yet implemented. - -Temperatures are measured in degrees Celsius and measurement resolution is 1 -degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when -the temperature gets higher than the Overtemperature Shutdown value; it stays -on until the temperature falls below the Hysteresis value. - -Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4, 8, 16, 32, 64 or -128) to give the readings more range or accuracy. This driver modifies the -fan divisor automatically to get the reasonable RPM rotation range. - -Voltage sensors (also known as IN sensors) report their values in volts. -An alarm is triggered if the voltage has crossed a programmable minimum -or maximum limit. - -Alarms are provided as output from "realtime status register". Following bits -are defined: - -bit - alarm on: -0 - in0 -1 - in1 -2 - temp1 -3 - temp2 -4 - temp3 -5 - fan1 -6 - fan2 -7 - fan3 -8 - in2 -9 - in3 -10 - in4 -11 - in5 -12 - in6 -13 - VID change -14 - chassis -15 - fan7 -16 - tart1 -17 - tart2 -18 - tart3 -19 - in7 -20 - in8 -21 - fan4 -22 - fan5 -23 - fan6 - -Tart will be asserted while target temperature cannot be achieved after 3 minutes -of full speed rotation of corresponding fan. - -In addition to the alarms described above, there is a CHAS alarm on the chips -which triggers if your computer case is open (This one is latched, contrary -to realtime alarms). - -The chips only update values each 3 seconds; reading them more often will -do no harm, but will return 'old' values. - - -W83792D PROBLEMS ----------------- -Known problems: - - This driver is only for Winbond W83792D C version device, there - are also some motherboards with B version W83792D device. The - calculation method to in6-in7(measured value, limits) is a little - different between C and B version. C or B version can be identified - by CR[0x49h]. - - The function of vid and vrm has not been finished, because I'm NOT - very familiar with them. Adding support is welcome. - - The function of chassis open detection needs more tests. - - If you have ASUS server board and chip was not found: Then you will - need to upgrade to latest (or beta) BIOS. If it does not help please - contact us. - - -Chip Features -------------- - -Chip `w83792d' - LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE - in0 NONE NONE R 3 - in1 NONE NONE R 3 - in2 NONE NONE R 3 - in3 NONE NONE R 3 - in4 NONE NONE R 3 - in5 NONE NONE R 3 - in6 NONE NONE R 3 - in7 NONE NONE R 3 - in8 NONE NONE R 3 - in0_min in0 in0 RW 3 - in1_min in1 in1 RW 3 - in2_min in2 in2 RW 3 - in3_min in3 in3 RW 3 - in4_min in4 in4 RW 3 - in5_min in5 in5 RW 3 - in6_min in6 in6 RW 3 - in7_min in7 in7 RW 3 - in8_min in8 in8 RW 3 - in0_max in0 in0 RW 3 - in1_max in1 in1 RW 3 - in2_max in2 in2 RW 3 - in3_max in3 in3 RW 3 - in4_max in4 in4 RW 3 - in5_max in5 in5 RW 3 - in6_max in6 in6 RW 3 - in7_max in7 in7 RW 3 - in8_max in8 in8 RW 3 - fan1 NONE NONE R 0 - fan2 NONE NONE R 0 - fan3 NONE NONE R 0 - fan4 NONE NONE R 0 - fan5 NONE NONE R 0 - fan6 NONE NONE R 0 - fan7 NONE NONE R 0 - fan1_min fan1 NONE RW 0 - fan2_min fan2 NONE RW 0 - fan3_min fan3 NONE RW 0 - fan4_min fan4 NONE RW 0 - fan5_min fan5 NONE RW 0 - fan6_min fan6 NONE RW 0 - fan7_min fan7 NONE RW 0 - temp1 NONE NONE R 1 - temp1_hyst temp1 temp1 RW 1 - temp1_over temp1 temp1 RW 1 - temp2 NONE NONE R 1 - temp2_hyst temp2 temp2 RW 1 - temp2_over temp2 temp2 RW 1 - temp3 NONE NONE R 1 - temp3_hyst temp3 temp3 RW 1 - temp3_over temp3 temp3 RW 1 - fan1_div fan1 NONE RW 0 - fan2_div fan2 NONE RW 0 - fan3_div fan3 NONE RW 0 - fan4_div fan4 NONE RW 0 - fan5_div fan5 NONE RW 0 - fan6_div fan6 NONE RW 0 - fan7_div fan7 NONE RW 0 - - LABEL FEATURE SYMBOL SYSCTL FILE:NR - in0 SENSORS_W83792D_IN0 in0:3 - in1 SENSORS_W83792D_IN1 in1:3 - in2 SENSORS_W83792D_IN2 in2:3 - in3 SENSORS_W83792D_IN3 in3:3 - in4 SENSORS_W83792D_IN4 in4:3 - in5 SENSORS_W83792D_IN5 in5:3 - in6 SENSORS_W83792D_IN6 in6:3 - in7 SENSORS_W83792D_IN7 in7:3 - in8 SENSORS_W83792D_IN8 in8:3 - in0_min SENSORS_W83792D_IN0_MIN in0:1 - in1_min SENSORS_W83792D_IN1_MIN in1:1 - in2_min SENSORS_W83792D_IN2_MIN in2:1 - in3_min SENSORS_W83792D_IN3_MIN in3:1 - in4_min SENSORS_W83792D_IN4_MIN in4:1 - in5_min SENSORS_W83792D_IN5_MIN in5:1 - in6_min SENSORS_W83792D_IN6_MIN in6:1 - in7_min SENSORS_W83792D_IN7_MIN in7:1 - in8_min SENSORS_W83792D_IN8_MIN in8:1 - in0_max SENSORS_W83792D_IN0_MAX in0:2 - in1_max SENSORS_W83792D_IN1_MAX in1:2 - in2_max SENSORS_W83792D_IN2_MAX in2:2 - in3_max SENSORS_W83792D_IN3_MAX in3:2 - in4_max SENSORS_W83792D_IN4_MAX in4:2 - in5_max SENSORS_W83792D_IN5_MAX in5:2 - in6_max SENSORS_W83792D_IN6_MAX in6:2 - in7_max SENSORS_W83792D_IN7_MAX in7:2 - in8_max SENSORS_W83792D_IN8_MAX in8:2 - fan1 SENSORS_W83792D_FAN1 fan1:2 - fan2 SENSORS_W83792D_FAN2 fan2:2 - fan3 SENSORS_W83792D_FAN3 fan3:2 - fan4 SENSORS_W83792D_FAN4 fan4:2 - fan5 SENSORS_W83792D_FAN5 fan5:2 - fan6 SENSORS_W83792D_FAN6 fan6:2 - fan7 SENSORS_W83792D_FAN7 fan7:2 - fan1_min SENSORS_W83792D_FAN1_MIN fan1:1 - fan2_min SENSORS_W83792D_FAN2_MIN fan2:1 - fan3_min SENSORS_W83792D_FAN3_MIN fan3:1 - fan4_min SENSORS_W83792D_FAN4_MIN fan4:1 - fan5_min SENSORS_W83792D_FAN5_MIN fan5:1 - fan6_min SENSORS_W83792D_FAN6_MIN fan6:1 - fan7_min SENSORS_W83792D_FAN7_MIN fan7:1 - temp1 SENSORS_W83792D_TEMP1 temp1:3 - temp1_hyst SENSORS_W83792D_TEMP1_HYST temp1:2 - temp1_over SENSORS_W83792D_TEMP1_OVER temp1:1 - temp2 SENSORS_W83792D_TEMP2 temp2:3 - temp2_hyst SENSORS_W83792D_TEMP2_HYST temp2:2 - temp2_over SENSORS_W83792D_TEMP2_OVER temp2:1 - temp3 SENSORS_W83792D_TEMP3 temp3:3 - temp3_hyst SENSORS_W83792D_TEMP3_HYST temp3:2 - temp3_over SENSORS_W83792D_TEMP3_OVER temp3:1 - fan1_div SENSORS_W83792D_FAN1_DIV fan_div:1 - fan2_div SENSORS_W83792D_FAN2_DIV fan_div:2 - fan3_div SENSORS_W83792D_FAN3_DIV fan_div:3 - fan4_div SENSORS_W83792D_FAN4_DIV fan_div:4 - fan5_div SENSORS_W83792D_FAN5_DIV fan_div:5 - fan6_div SENSORS_W83792D_FAN6_DIV fan_div:6 - fan7_div SENSORS_W83792D_FAN7_DIV fan_div:7 - - - - -/PROC ENTRIES -------------- -Most are identical to the w83781d entries. See the w83781d documentation for -details. - -Most of the additional entries not in the w83781d are Winbond Smart Fan I/II: -Please read "7.7 FAN Speed Count and FAN Speed Control" of W83792AD/D datasheet -before you read the explanation to the /proc entries below. - - fan_cfg: indicates the fan speed control mode: 0 means PWM/DC mode, - 1 means Smart Fan I(Thermal Cruise) mode, 2 or 3 means Smart Fan II - mode. There are three items in this entry, the first one is the - configuration of Fan1, the rest may be deduced by analogy. - - pwm_flag: valid under PWM/DC mode, 1 means PWM mode, 0 means DC mode. - There are three items in this entry, the first one is PWM/DC mode - of Fan1, the rest may be deduced by analogy. - - thermal_cruise: valid under Smart Fan I mode, indicates the wanted - temperature. There are three items in this entry, the first one - is setting temperature of Fan1, the rest may be deduced by analogy. - - fan_tolerance: valid under Smart Fan I or Smart Fan II mode, indicates - the interval temperature. There are also three items in this entry. - - sf2_points_fan1: valid under Smart Fan II mode, there are four items in - this entry, indicates the Temp.[1-4] in "Figure 8. Smart Fan II - behavior" to Fan1. - - sf2_points_fan2: almost same as the above one, except that this entry - is for Fan2. - - sf2_points_fan3: almost same as the above one, except that this entry - is for Fan3. - - sf2_levels_fan1: valid under Smart Fan II mode, there are four items in - this entry, indicates the "Non-Stop Duty Cycle" and "Fan Duty Cycle - Level [1-3]" in "Figure 8. Smart Fan II behavior" to Fan1. The - first item "Non-Stop Duty Cycle" is read only in this driver, while - the other three items can be modified. - - sf2_levels_fan2: almost same as the above one, except that this entry - is for Fan2. - - sf2_levels_fan3: almost same as the above one, except that this entry - is for Fan3. - - -additional entries for chassis intrusion detection: - chassis: There are two items in this entry, the first one indicats the - chassis status, 1 means chassis intrusion detected, while 1 means - normal. The second item in this entry is used to clear the - detected chassis intrusion interrupt and reset the chassis status - to normal. diff --git a/doc/chips/w83l785ts b/doc/chips/w83l785ts deleted file mode 100644 index 16972072..00000000 --- a/doc/chips/w83l785ts +++ /dev/null @@ -1,77 +0,0 @@ -Kernel driver `w83l785ts.o' -=========================== - -Status: Beta, slightly tested - -Supported chips: - * Winbond W83L785TS-S - Prefix: 'w83l785ts' - Addresses scanned: I2C 0x2e - Datasheet: Publicly available at the Winbond USA website - http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf - - -Author: Jean Delvare - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_w83l785ts: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `w83l785ts' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan - - -Description ------------ - -The W83L785TS-S is a digital temperature sensor. It senses the -temperature of a single external diode. The high limit is -theoretically defined as 85 or 100 degrees C through a combination -of external resistors, so the user cannot change it. Values seen so -far suggest that the two possible limits are actually 95 and 110 -degrees C. The datasheet is rather poor and obviously inaccurate -on several points including this one. - -All temperature values are given in degrees Celsius. Resolution -is 1.0 degree. See the datasheet for details. - -The w83l785ts driver will not update its values more frequently than -every other second; reading them more often will do no harm, but will -return 'old' values. - - -Known Issues ------------- - -On some systems (Asus), the BIOS is known to interfere with the driver -and cause read errors. The driver will retry a given number of times -(5 by default) and then give up, returning the old value (or 0 if -there is no old value). It seems to work well enough so that you should -not notice anything. Thanks to James Bolt for helping test this feature. - - -Chip Features -------------- - -Chip 'w83l785ts' - -LABEL LABEL CLASS COMPUTE CLASS MODE MAGN -temp - - R- 0 -temp_high temp temp R- 0 - -LABEL FEATURE SYMBOL SYSCTL FILE:N -temp SENSORS_W83L785TS_TEMP temp:2 -temp_high SENSORS_W83L785TS_TEMP_OVER temp:1 diff --git a/doc/chips/xeontemp b/doc/chips/xeontemp deleted file mode 100644 index a77a214a..00000000 --- a/doc/chips/xeontemp +++ /dev/null @@ -1,108 +0,0 @@ -Kernel driver `xeontemp.o' -========================= - -Status: Complete; tested for most devices except Xeon. - -Supported chips: - * Intel Xeon and other processors - Prefix: 'xeontemp' - Addresses scanned: I2C 0x18, 0x1a, 0x29, 0x2b, 0x4c, 0x4e - Datasheets: Publicly available at the Intel website - See the adm1021 document for additional references - -Authors: Frodo Looijaard ,Philip Edelbrock - , and Mark D. Studebaker (mdsxyz123@yahoo.com) - -License: GPL - - -Module Parameters ------------------ - -* force: short array (min = 1, max = 48) - List of adapter,address pairs to boldly assume to be present -* force_xeontemp: short array (min = 1, max = 48) - List of adapter,address pairs which are unquestionably assumed to contain - a `xeontemp' chip -* probe: short array (min = 1, max = 48) - List of adapter,address pairs to scan additionally -* probe_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples to scan additionally -* ignore: short array (min = 1, max = 48) - List of adapter,address pairs not to scan -* ignore_range: short array (min = 1, max = 48) - List of adapter,start-addr,end-addr triples not to scan -* read_only: int - Don't set any values, read only mode - - -Description ------------ - -Many Xeons and other Intel processors have an embedded i2c temperature -sensor that look very similar to an adm1021 or max1617. - -Some Xeons have honest to goodness, real live, actual MAX1617 chips on -them. Others Xeons made around the same time have other ADM1021 -compatible chips on them. They are mounted on the CPU substrate along -with the processor information EEPROM that is part of that generation of -Xeon CPU's. - -So it's basically impossible to tell a Xeon TEMP sensor from a MAX1617 -since they are in fact the same chip. The Xeon Temperature sensors spec -is just a stripped down register spec for the ADM1021 that says the -"on-board" or "built-in" sensor registers are "reserved". That way -Intel could substitute whatever ADM1021 compatible chip was cheapest at -the time when they built the CPU's. - -One reason to use the xeontemp driver is if, when Intel built your -particular Xeon's, they didn't use any of the ADM1021 compatible chips -that the ADM1021 driver recognizes. In that case, using the xeontemp -driver will get you the temperatures you want without potentially -messing up something in the sensor. - -Another reason is to avoid having 'sensors' report the second -temperature. - -Unfortunately, the 533MHz FSB Xeon's, dropped the on-board sensor chip. -So these new Xeons require a sensor on the motherboard to be connected -to the thermal diode to read the temperature. But these 533MHz capable -motherboards can also accept 400MHz CPU's with the on-board sensor so it -gets confusing in a hurry for motherboard vendors and users. - -If you have 400MHz FSB P4 Xeon CPU's, you should have an on-CPU ADM1021 -compatible sensor at 0x18 or 0x19. In that case, use the ADM1021 driver -if it detects a chip at that address. The CPU DIE temperature (Tj) will -be the "REMOTE" temperature from this sensor. The "Board" or "built-in" -temperature from the ADM1021 will be the temperature of the ADM1021 -compatible itself which is one of the chips you see on the side of the CPU. - -If you have sensors at 0x18 and 0x19 that are not detected by the -ADM1021, and you have 400MHz Xeons, then you may want to try the -xeontemp driver. - -If you have 533MHZ FSB Xeons, then you do *not* have an on-board thermal -sensor and you should look for CPU temperatures from the other sensors -on your motherboard. (Winbond chip for example). - -If you have an Intel Xeon processor, and sensors-detect recommended -the adm1021 driver, and the address is one of -0x18, 0x1a, 0x29, 0x2b, 0x4c, or 0x4e, and when using the -adm1021 driver, temp1 is invalid but temp2 looks correct, then -it is likely you should use the xeontemp driver instead. - -If you have dual Xeons you may have appear to have two separate -adm1021-compatible chips, or two single-temperature sensors, -at distinct addresses. - -In summary, the xeontemp module supports one temperature and the -adm1021 module supports two. Use the module that works best for you. - -See the adm1021 documentation for more information. - - -Author/Maintainer ------------------ -Mark D. Studebaker (mdsxyz123@yahoo.com). -Derived from the adm1021 driver. -Thanks to Philip Pokorny for help with this document. diff --git a/doc/developers/design b/doc/developers/design deleted file mode 100644 index 045fb1a3..00000000 --- a/doc/developers/design +++ /dev/null @@ -1,550 +0,0 @@ -This is a design for version 2 of our smbus and lm_sensors module. This -document is Copyright (c) 1998, 1999 by Frodo Looijaard. You may freely copy and -distribute it, as long as you recognize me as the author, and mark any -changes you make as being your own, and distribute this notice with it. - -Document version 1.0, 19981101. - 1.1, 19981111. - 1.2, 19981118. - 1.3, 19981126. - -NOTE: THIS IS BY NOW SOMEWHAT OUTDATED. SORRY. - - -Object oriented approach -======================== - -The i2c module structs contain callback functions and data fields. In the -i2c module, these structures are only referenced by pointers. This makes -it easy to extend these structs to contain additional information or -callback functions. For those familiar with object oriented languages, -you can see the smbus and isa structures as an object extension of the i2c -structures. - -To make this clearer, I will show in an example how this is done. Note -that I have simplified some things here, so this example does not -correspond to an actual struct found in one of the modules. - -In the i2c module, you can find a struct somewhat like this: - -struct i2c_adapter { - char name[32]; - int (*detach_client) (struct i2c_client *); - struct i2c_adapter *next; -} - -We have a plain data field (name), a call-back function which needs one -parameter (a pointer to a i2c_client struct), and a data field which is -a pointer to the next adapter. - -Now we want to extend this structure. We need another data field, -containing a number of flags. We will call this new structure smbus_adapter. -A few other things change too: - -struct smbus_adapter { - char name[32]; - int (*detach_client) (struct smbus_client *); - struct smbus_adapter *next; - unsigned int flags; -} - -So we copy all existing fields. The next field still points to the next -adapter - but it is now of type smbus_adapter, not i2c_adapter. And the -call-back function takes now a parameter of type pointer to smbus_client. -And there is a new data field, called flags. - -Now examine this function definition: - -int fully_detach_i2c_client (struct i2c_client * client) -{ - res = 0; - struct i2c_adapter *current_adapter = first_adapter; /* a global var. */ - while (current_adapter) { - res |= (current_adapter -> detach_client) (client); - current_adapter = current_adapter -> next; - } - return res; -} - -This function detaches a client from all adapters. Nice. But now comes the -Big Trick(tm): we can still use this function for smbus_adapters! - -int fully_detach_smbus_client (struct smbus_client * client) -{ - return fully_detach_i2c_client( (struct i2c_client *) client); -} - -All we needed here was a simple typecast. Datapointers remain datapointers, -so this can safely be done. And because we use call-back functions, the -actual function called to detach a client from a single adapter might -be the same, or different, depending on what function was put in -client->detach_client! - -It gets even better. The i2c module stores internally all registered -adapters. But it stores pointers to the i2c_adapter struct, not the -structs themselves! So there is an array: - -#define I2C_ADAPTER_MAX 32 -struct i2c_adapter *adapters[I2C_ADAPTER_MAX]; -/* this is an array of pointers to structs, not vice versa! */ - -So, an element of this array might in fact point to a smbus_adapter, instead -of an i2c_adapter! If you know this for sure, you might use a typecast and -access the additional fields. In the meantime, the i2c internal -administration remains valid. - -We have to thank Simon Vogl and Gerd Knorr for the way they implemented -their i2c module. Any other way would have made this approach impossible, -and basing anything upon their module much more difficult. - -Limitations ------------ - -Extending the adapter and algorithm structures in this way is quite safe. -They are only allocated on places where the code knows that they are -'special'. Extending the driver or client structures depending on a -specific adapter/algorithm type is *very* *dangerous*. A driver/client -module would need to be aware of every special adapter/algorithm in -order to allocate itself! For the ISA bus, it has to be aware of this -anyway, so it is safe to do; on other places, think twice first! - - -Module overview -=============== - -All in all, lots of modules will be stacked on each other. Too bad, but -that is the only way to cleanly implement everything. Note that in a -specific situation, only a few modules may need to be loaded. isa.o, -for example, does not depend on smbus.o (in the sense that you can load -sensor.o without loading smbus.o). A specific bus driver, though, will -depend on many of them. - -Generally: - isa.o depends on nothing (actually, on i2c.o, to keep the code small) - smbus.o depends on nothing (actually, on i2c.o, to keep the code small) - i2c.o depends on nothing. - - A non-i2c SMBus bus driver depends only on smbus.o - A i2c bus driver depends only on i2c.o - - A sensor chip driver depends either on isa.o or smbus.o, or both. - A SMBus chip driver depends only on smbus.o - A I2C chip driver depends only on i2c.o - -We may need a sensor.o module, to act as a central point for sensor -modules. At this moment, it seems not really necessary, but this may -change. - -We will need an enhanced i2c-dev.o module, to add SMBus access to I2C -/dev entries. - - -isa.o -ISA bus handling. -Encapsulates ISA bus access within the i2c structures. -Unites I2C adapters and the ISA bus. -Defines variables isa_algorithm and isa_adapter. - -smbus.o -Main SMBus handling. -Encapsulates SMBus access within the smbus structures. -Unites I2C adapters and SMBus hosts (like the PIIX4). -Emulates SMBus access on pure I2C adapters. -Defines variable smbus_algorithm. - - piix4.o - SMBus adapter driver for the PIIX4 SMBus host. - Defines variable piix4_adapter (based on smbus_algorithm). - - FOO.o - Adapter driver for FOO SMBus host - Defines variable FOO_adapter (based on smbus_algorithm). - -i2c-core.o (From Simon Vogl) -Main i2c handling. - - ????.o - I2C adapter driver - Implementing a class of I2C busses - - -A chip driver (typically defined in its own module) can be hooked on all -these levels: - * If it is a sensor chip, it should be hooked to isa.o or smbus.o - * A pure ISA chip should be hooked to isa.o - * A pure SMBus chip should be hooked to smbus.o - * An I2C chip should be hooked to i2c.o -It can be difficult to decide whether a specific chip should be hooked to -smbus.o or i2c.o. A good deciding question is, 'could it be connected to -a PIIX4?' - - -Module i2c.o -============ - -This is Simon Vogl's i2c module (this one is different from the i2c module -included in kernels around 2.1.120!). - -A driver --------- - -struct i2c_driver { - char name[32]; - int id; - unsigned int flags; - int (* attach_adapter) (struct i2c_adapter *); - int (* detach_client) (struct i2c_client *); - int (* command) (struct i2c_client *, unsigned int cmd, void *arg); - void (* inc_use) (struct i2c_client *); - void (* dec_use) (struct i2c_client *); -} - -A driver tells us how we should handle a specific type of i2c chip. An -instance of such a chip is called a 'client'. An example would be the LM75 -module: it would contain only one driver, which tells us how to handle the -LM75; but each detected LM75 would be a separate client (which would be -dynamically allocated). - - -A description of the above struct: - name: The name of this driver - id: A unique driver identifier - flags: Flags to set certain kinds of behaviour. Most notably, DF_NOTIFY - will notify the driver when a new i2c bus is detected, so it can - try to detect chips on it. - attach_adapter: A call-back function which is called if a new adapter (bus) - is found. This allows us to do our detection stuff on the new adapter, - and register new clients. - detach_client: A call-back function which is called if a specific client - which uses this driver should be disallocated. If a specific sensor module - is removed, for instance, this function would be called for each registered - client. - command: A generic call-back function to communicate in a driver-dependent - way with a specific client. This should only be seldom needed. - inc_use: Can be called to add one to an internal 'use' counter. This can be - used to control when it is safe to remove this module, for example. - - -A client --------- - -struct i2c_client { - char name[32]; - int id; - unsigned int flags; - unsigned char addr; - struct i2c_adapter *adapter; - struct i2c_driver *driver; - void *data; -} - -A client is a specific sensor chip. Its operation is controlled by a driver -(which describes a type of sensor chip), and it is connected to an adapter -(a bus). - -A description of the above struct: - name: The name of this client - id: A unique client id - flags: Flags to set certain kinds of behaviour (not very important) - addr: The client address. 10-bit addresses are a bit of a kludge right now. - adapter: A pointer to the adapter this client is on. - driver: A pointer to the driver this client uses. - data: Additional, client-dependent data - - -An algorithm ------------- - -struct i2c_algorithm { - char name[32]; - unsigned int id; - int (* master_xfer) (struct i2c_adapter *adap, struct i2c_msg msgs[], - int num); - int (* slave_send) (struct i2c_adapter *,char *, int); - int (* slave_recv) (struct i2c_adapter *,char *, int); - int (* algo_control) (struct i2c_adapter *, unsigned int, unsigned long); - int (* client_register) (struct i2c_client *); - int (* client_unregister) (struct i2c_client *); -} - -An algorithm describes how a certain class of i2c busses can be accessed. - -A description of the above struct: - name: The name of this algorithm - id: A unique algorithm id - master_xfer: Transfer a bunch of messages through a specific i2c bus. - slave_send: Send a message as if we are a slave device - slave_recv: Receive a message as if we are a slave device - client_register: Register a new client - client_unregister: Unregister a client - - -An adapter ----------- - -struct i2c_adapter { - char name[32]; - unsigned int id; - struct i2c_algorithm *algo; - void *data; -#ifdef SPINLOCK - spinlock_t lock; - unsigned long lockflags; -#else - struct semaphore lock; -#endif - unsigned int flags; - struct i2c_client *clients[I2C_CLIENT_MAX]; - int client_count; - int timeout; - int retries; -} - -An adapter is a specific i2c bus. How to access it is defined in the -algorithm associated with it. - -A description of the above struct: - name: The name of this adapter - id: A unique adapter id - algo: The algorithm through which this bus must be accessed - data: Adapter specific data - lock, lockflags: To lock out simultaneous adapter access - flags: Modifiers for adapter operation - clients: All currently connected clients - client_count: The number of currently connected clients - timeout, retries: Internal variables (unimportant here). - - -Access functions ----------------- - -All these functions are defined extern. - -int i2c_master_send(struct i2c_client *,const char *, int); -int i2c_master_recv(struct i2c_client *,char *, int); -int i2c_transfer(struct i2c_adapter *,struct i2c_msg [], int num); - -These function respectively send one message to a client, receive one message -from a client, or transmit a bunch of messages. struct i2c_msg contains -an i2c address to communicate with, and can both read from and write to this -address. - - -int i2c_slave_send(struct i2c_client *, char *, int); -int i2c_slave_recv(struct i2c_client *, char *, int); - -Communicate with another master as if the normal master is a common slave -device. - - -Administration functions ------------------------- - -int i2c_add_algorithm(struct i2c_algorithm *); -int i2c_del_algorithm(struct i2c_algorithm *); - -The i2c_{add,del}_algorithm functions must be called whenever a new module -is inserted with this driver in it, by the module initialization function. - - -int i2c_add_adapter(struct i2c_adapter *); -int i2c_del_adapter(struct i2c_adapter *); - -The i2c_{add,del}_adapter functions must be called if you have detected -a specific bus. It triggers driver->attach_adapter (add, for each driver -present) or driver->detach_client (del, for each registered client on -this adapter). - - -int i2c_add_driver(struct i2c_driver *); -int i2c_del_driver(struct i2c_driver *); - -The i2c_{add,del}_driver functions must be called whenever a new module is -inserted with a chip driver in it, by the module initialization function. - - -int i2c_attach_client(struct i2c_client *); -int i2c_detach_client(struct i2c_client *); - -The i2c_{attach,detach}_client functions must be called if you have detected -a single chip. - - -Module smbus.o -============== - -This module offers support for SMBus operation. An SMBus adapter can either -accept SMBus commands (like the PIIX4), or be in fact an I2C driver. In -the last case, all SMBus commands will be expressed through I2C primitives. -This means that any I2C adapter driver will automatically be a SMBus -driver. - -At this point, it should be noted that there can only be one System -Management Bus in a given system (is this really true, by the way?). This -means there must be some way of selecting which of the many possible adapters -is in fact *the* SMBus. For now, I will ignore this problem. Later on, -we can add a hook somewhere in the i2c module to help us decide this. - -This module consists in fact of three separate parts: first of all, it extends -all i2c structs to accomodate the new smbus fields. Second, it defines a -new algorithm (smbus_algorithm), that will be used by all non-i2c adapters. -Finally, it implements a new access function that sends or receives SMBus -commands; these are either translated into I2C commands or sent to the -SMBus driver. - - -A driver, client and algorithm ------------------------------- - -We will not need to extend i2c_driver, i2c_client or i2c_adapter. This means -that struct smbus_driver is exactly the same as struct i2c_driver, and -struct smbus_client is the same as struct i2c_client, and smbus_adapter is -the same as struct i2c_adapter. We *will* define the smbus_* variants, and -use them within this module, so it should be easy to extend them after all. - -Note that at this moment, 10 bit SMBus addresses seem to be only -partially supported by the i2c module. We will ignore this issue for -now. - - -An adapter ------------- - -struct smbus_adapter { - char name[32]; - unsigned int id; - struct smbus_algorithm *algo; - void *data; -#ifdef SPINLOCK - spinlock_t lock; - unsigned long lockflags; -#else - struct semaphore lock; -#endif - unsigned int flags; - struct smbus_client *clients[I2C_CLIENT_MAX]; - int client_count; - int timeout; - int retries; - - /* Here ended i2c_adapter */ - s32 (* smbus_access) (__u8 addr, char read_write, - __u8 command, int size, union smbus_data * data); -} - -A description of the above struct: - smbus_access: A function to access the SMBus. It is only used for non-i2c - smbus adapters. - - -Access functions ----------------- - -All these functions are defined extern. - -The i2c access function should not be used within SMBus chip drivers, as -they might not be defined (for the PIIX4, for example). Instead, use the -following general access function, or one of the easier functions based -on it: - -int smbus_access (struct i2c_adapter *, __u8 addr, char read_write, - __u8 command, int size, union smbus_data * data); - -There are specific SMBus registration functions too, like the i2c ones. -They are fully compatiable with each other; just substitute 'smbus' for -'i2c' everywhere in the i2c description. - -int i2c_is_smbus_client(struct i2c_client *); -int i2c_is_smbus_adapter(struct i2c_adapter *); - -Decide whether this client, or adapter, is (on) a non-I2C SMBus. Usually -not needed, but it is nice anyway to be able to decide this. - - -Module isa.o -============ - -This module implements a new algorithm and a specific adapter for the -(single) ISA bus in your computer. This makes writing drivers for chips -that can be both on ISA and SMBus much easier. - -Note that this module does *not* in any way depend on smbus.o (previous -versions of this document still assumed it would be build upon it; this -is no longer true). - - -A driver, adapter or algorithm ------------------------------- - -We will not need to extend i2c_driver, i2c_adapter or i2c_algorithm. This -means that struct isa_driver is exactly the same as struct i2c_driver, -struct isa_adapter is the same as struct i2c_adapter and struct isa_algorithm -is the same as struct isa_driver. We *will* define the isa_* variants, and -use them within this module, so it should be easy to extend them after all. - - -A client --------- - -struct isa_client { - char name[32]; - int id; - unsigned int flags; - unsigned char addr; - struct isa_adapter *adapter; - struct isa_driver *driver; - void *data; - - unsigned int isa_addr; -} - -A client is a specific sensor chip. Its operation is controlled by a driver -(which describes a type of sensor chip), and it is connected to an adapter -(a bus, the (single) ISA bus here). - -A description of the above struct: - isa_addr: ISA addresses do not fit in the i2c-compatible addr field, so - we needed a new field. - - -Access functions ----------------- - -All these functions are defined extern. - -In case of the ISA bus, the master_xfer, slave_send and slave_recv hooks -will be NULL, because these functions make no sense. It is regrettably -not easy to create an access abstraction in which both ISA bus access -and SMBus access are united. See below for examples how you can solve -this problem. - -The most imporant additional access function: - -int i2c_is_isa_client(struct i2c_client *); -int i2c_is_isa_adapter(struct i2c_adapter *); - -Decide whether this client, or adapter, is (on) the ISA bus. This is -important, because it determines whether we can use the SMBus access -routines. - -As an example, I will here implement our old LM78 access function: - -/* The SMBus locks itself, but ISA access must be locked explicitly! - We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM78 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ -int lm78_read_value(struct i2c_client *client, u8 reg) -{ - int res; - if (i2c_is_isa_client(client)) { - down((struct semaphore *) (client->data)); - outb_p(reg,(((struct isa_client *) client)->isa_addr) + - LM78_ADDR_REG_OFFSET); - res = inb_p((((struct isa_client *) client)->isa_addr) + - LM78_DATA_REG_OFFSET); - up((struct semaphore *) (client->data)); - return res; - } else - return smbus_read_byte_data(client->adapter,client->addr, reg); -} diff --git a/doc/developers/makefiles b/doc/developers/makefiles index b94b50be..59c28fc8 100644 --- a/doc/developers/makefiles +++ b/doc/developers/makefiles @@ -4,36 +4,28 @@ See doc/useful_addresses.html for a link to this article. There is one big Makefile in the root of this package. It includes many other files; one for each directory in which source code is found. These -included files are called 'Module.mk'. There is a separate set of Makefiles -in the i2c/ directories; these are Simon Vogl's original Makefiles, and -not referred by the main package Makefile. +included files are called 'Module.mk'. There are several interesting targets defined through this Makefile: * all Create everything in all directories. - * all-i2c, all-src, ... - Create everything in the designated directory. * install Install everything from all directories. - * install-i2c, install-src, ... - Install everything in the designated directory. + * uninstall + Uninstall everything. * clean Remove anything which can be regenerated from all directories. A call of 'make clean' (without any other targets) will ignore any .d files; this is useful when they are out of date (and prevent the calling of any other target). - * clean-i2c, clean-src, ... - Remove anything which can be regenerated from the designated directory. * version Regenerate version.h, using the current date for the date-stamp, and a user-supplied version number. * package Create a .tar.gz file containing everything except the SVN directories. - * src/lm78.o, i2c/i2c-core.o, ... - You can of course also specify one or more targets to make. The best way to understand the Module.mk subfiles is to examine one of them, -for example src/Module.mk. They are not too difficult to understand. +for example lib/Module.mk. They are not too difficult to understand. There are several variables which can be set in the main Makefile. You can also specify them on the command-line; this overrules any definitions @@ -47,16 +39,12 @@ ones for developers: only output more information, and never make the code mis-behave. Several files are generated by Makefiles: - * .d - Dependency files for modules. Automatically generated. * .rd Dependency files for executables. Automatically generated. * .ao Dependency files for static libraries. Automatically generated. * .lo Dependency files for shared libraries. Automatically generated. - * .o - Generated modules * .ro Object files for executables. They will be linked together to create the executable. This extension is used to distinguish them from diff --git a/doc/developers/new_drivers b/doc/developers/new_drivers deleted file mode 100644 index db28421e..00000000 --- a/doc/developers/new_drivers +++ /dev/null @@ -1,166 +0,0 @@ -These are the steps you should follow to write a new driver and -submit it to us so that it will be applied cleanly to our package. -See at the bottom for adding new chip support to an existing driver. - -Don't be intimidated by the list, it's just here so we don't -forget anything. -We are more than happy to help you with any part of the process. - -There are two types of drivers, chip and bus. -Steps which apply to only one type of driver are noted. - -These instructions are for 2.4-kernel-compatible drivers. -If you wish to write a driver for 2.6 only, not all of the following -steps apply. - ---------------------------------------------------------------------- - -* Check our "New Drivers" page for status!! - -* Contact us. - You are of course free to write your own drivers, but it is smart to - check first nobody else is already working on it, in case the - New Drivers page is out of date. - Tell us it's OK to put your name on the "New Drivers" page. - -* Consider subscribing to the mailing list. - -* Check out our latest code from SVN. - You should use this as a base for your development. - See instructions on our download page. - -* Write the new driver. - If you write a driver for a device that is similar to one we already - support, use the other device driver as a template. If you don't know - which one to use, either ask us or use the following defaults. - For a chip driver, use lm78.c as template. For an SMBus-only adapter, - use i2c-piix4.c. Use i2c-via.c for an I2C-level adapter ('bit banger'). - Usually, we make all prefixes start with the driver name. This is not - really necessary, as these symbols will not be exported anyway. But by - doing this, you are sure you do not shadow any global kernel names. - -* A quick note about conversions. The conversions which are specified - in the sensor chip datasheet and which *cannot* vary from one board to - the next are performed by the driver. If other conversions are - necessary, they are performed in user-space. - -* Meet Kernel coding standards. - See Documentation/CodingStyle in the kernel source. - Be sure and use 8 column tabs. - Also, please do not use // comments. - Also, please do not go past column 80. - Also, please use C99 struct initializers {.foo = blat} - Please do this _before_ you check in your driver. - -* Meet /proc naming standards in the ctl_table (for chip drivers only). - See doc/developers/proc for information. Please do not deviate from - this without discussion. - -* Add the driver to the Module.mk (the makefile). - Usually, you can just add it to KERNEL{CHIPS,DRIVERS}TARGETS in the - Module.mk file in the directory itself. - -* Make sure it compiles cleanly. - Check compilation with 'make DEBUG=1' if you use debugging - information. Remember, things put between #ifdef DEBUG #endif may never - stop the driver from functioning; they should just output additional - information. - -* Check for external symbols. - 'nm --extern --defined' should only output symbols starting with __module, - cleanup_module, init_module and some kernel versioning symbols. Mark all - other symbols as static in your source file. - -* Test the module. - Test with a recent 2.4 kernel. - For bus drivers, use i2cdetect and i2cdump. For i2cdump, test all supported - bus access modes (see i2cdump man page). - For chip drivers, cat all files in applicable /proc or /sys directory - and check for problems. Write all supported settings. - Check ALARM indications. - -* Add detection information to prog/detect/sensors-detect. - This is a perl script that automatically detects what chips and adapters - are present. Contact us if you need help. - -* Add chip information to lib/chips.{c,h} (for chip drivers only). - Until you have done this, the chip will be invisible for user-level - programs which use libsensors. Use standard names in lib/chips.c; - see also the comments in etc/sensors.conf.eg for help. - Contact us if you need more assistance. - -* Be sure that SYSCTL and ALARM definitions in the driver are bracketed - by the special comments so that the kernel/include/sensors.h - file, which is generated automatically, contains your definitions. - (for chip drivers only) - -* Add a procedure to prog/sensors/chips.[ch] (for chip drivers only). - This is a function specific for your driver that - makes the included 'sensors' program pretty-print your chip information. - -* Add an line for the procedure in the matches[] table in - prog/sensors/main.c (for chip drivers only). - This tells sensors to call your new procedure when the chip name matches. - -* Add entries to etc/sensors.conf.eg (for chip drivers only). - If needed, you can set defaults here. - -* Test the userspace apps (sensors-detect and sensors). - Test setting limits with sensors -s. - -* Add the name of the device to the README file. - -* Add your name to the CONTRIBUTORS file. - -* Add entries to the CHANGES file. Please keep in alphabetical order. - -* Write a doc/chips/xxx or doc/busses/xxx file. - -* Add entry to doc/chips/SUMMARY (for chip drivers only). - -* Clearly specify licensing and copyright. - Make sure the GPL boilerplate and your name - (or if applicable your company's name) is at the top of the - new driver so we know you are giving it to us under the GPL. - -* Submit the changes to us. - Do a 'svn update' to get in sync (things will have changed since - you started), then submit the changes to us as a patch against SVN. - -* If you want to have your driver integrated to Linux 2.6, you have to - port your driver to the new sysfs interface. Once done and preferably - after testing, submit a patch to our mailing list: see - http://www.lm-sensors.org/wiki/AuthorsAndContributors - Make sure to check the current status for your driver first: - http://www.lm-sensors.org/wiki/Kernel2.6 - http://www.lm-sensors.org/wiki/Devices - ---------------------------------------------------------------------- -Checklist for us to do on the webpage: - -* Add entry to 'supported drivers' page - -* Update entry on 'new drivers' page - ---------------------------------------------------------------------- -Checklist for _adding_ support for a chip to an _existing_ driver: - -* Make the changes to the driver itself. - -* Add detection information to prog/detect/sensors-detect. - -* Add a strncmp() call for the new prefix in prog/sensors/main.c - (chip drivers only). - -* Add entries for the new prefix to etc/sensors.conf.eg (chip drivers only). - -* Update doc/[chips,busses]/xxx file - -* Update doc/chips/SUMMARY file (chip drivers only) - -* Update list in README - -* Submit the changes as a patch or check them in - -* Update entry on 'new drivers' page - diff --git a/doc/developers/proc b/doc/developers/proc deleted file mode 100644 index 9286febb..00000000 --- a/doc/developers/proc +++ /dev/null @@ -1,145 +0,0 @@ -Naming and data format standards under /proc --------------------------------------------- - -The libsensors library offers an interface to the raw sensors data -through the sysctl interface. See the doc/developers/sysctl -and the libsensors source for further information. - -An alternative method that some programs use is to access the /proc -files directly. This document briefly describes the standards that -the drivers follow, so that an application program can scan for -entries and access this data in a simple and consistent way. - -Note that not all chip drivers adhere to this standard. -We will attempt to migrate older drivers to this standard, -and ensure that new drivers follow this standard wherever possible. -If you are developing a userspace application please send us -feedback on this standard. - -Note that motherboards vary widely in the connections to sensor chips. -There is no standard that ensures, for example, that the second -temperature sensor is connected to the CPU, or that the second -fan is on the CPU. Therefore, programs must provide a facility -for the user to label or bind /proc entries for display. -Sensor chips often have unused inputs that should be ignored -by user programs. - -Each chip gets its own directory under /proc/sys/dev/sensors. -The format is either chip-i2c-bus-hexaddress or chip-isa-hexaddress. -(Exception - chip lm78-j has a '-' in it - should this be changed??) -New dummy drivers may present chips as chip-busname-hexaddress. - -All /proc values are integers or floating point numbers. -There is no facility in the lm_sensors package for drivers -to output general strings via /proc. This facility may be added -in the future. - -Alarms are direct indications read from the chips. The drivers do NOT make -comparisons of readings to thresholds. This allows violations -between readings to be caught and alarmed. The exact definition of -an alarm (for example, whether a threshold must be met or must be -exceeded to cause an alarm) is chip-dependent. - -Guidelines for new entries: - - If there are multiple values, some r/w and some r/o, - put the r/w ones first. - - Additional non-standard values should be after the standard values. - - - -------------------------------------------------------------------------- - -/proc entries are as follows: - - -Entry Values Function ------ ------ -------- -alarms 1 Alarm bitmask. - Read only. - Integer representation of one to four bytes. - A '1' bit means an alarm. - Chips should be programmed for 'comparator' mode so that - the alarm will 'come back' after you read the register - if it is still valid. - Generally a direct representation of a chip's internal - alarm registers; there is no standard for the position - of individual bits. - Bits are defined in kernel/include/sensors.h. - -beep 2 Beep/interrupt enable and bitmask. - The first value is 0 or 1 to globally disable - or enable the beeps. - The second value is a bitmask, with the - same format as 'alarms' with same bit locations. - -curr[1-n] 3 Current max, min or hysteresis, and input value. - Floating point values XX.X or XX.XX in Amps. - The second value is preferably a hysteresis value, - reported as a absolute current, NOT a delta from - the max value. - First two values are read/write and third is read only. - -fan[1-3] 2 Fan minimum and input value. - Two integers indicating RPM. - First value is read/write and second is read only. - -fan_div 3 Fan divisor. - Integers in powers of two (1,2,4,8,16,32,64,128). - Some chips only support values 1,2,4,8. - Entries correspond to the fans[1-3]. - See doc/fan-divisors for details. - -in[0-8] 3 Voltage min, max, and input value. - Floating point values X.XX in volts from 0 to 4.01 volts. - Actual voltage depends on the scaling resistors on the - motherboard, as recommended in the chip datasheet. - This varies by chip and by motherboard. - Because of this variation, values are generally NOT scaled - by the chip driver, and must be done by the application. - However, some drivers (notably lm87 and via686a) - do scale, with various degrees of success. - These drivers will output the actual voltage. - First two values are read/write and third is read only. - Typical usage: - in0 CPU #1 voltage (not scaled) - in1 CPU #1 voltage (not scaled) - in2 3.3V nominal (not scaled) - in3 5.0V nominal (scaled) - in4 12.0V nominal (scaled) - in5 -12.0V nominal (scaled) - in6 -5.0V nominal (scaled) - in7 varies - in8 varies - -pwm[1-3] 1-2 Pulse width modulation fan control. - Integer 0 - 255, read/write. - 255 is max or 100%. - Corresponds to the fans 1-3. - Second value, if present, is an enable (0 or 1) - -sensor[1-3] 1 Sensor type selection. - Integers 1,2,3, or thermistor Beta value (3435); read/write. - -temp, -temp[1-4] 3 Temperature max, min or hysteresis, and input value. - Floating point values XXX.X or XXX.XX in degrees Celsius. - 'temp' is used if there is only one temperature sensor on the - chip; for multiple temps. start with 'temp1'. - Temp1 is generally the sensor inside the chip itself, - generally reported as "motherboard temperature". - Temp2 to temp4 are generally sensors external to the chip - itself, for example the thermal diode inside the CPU or a - termistor nearby. The second value is preferably a hysteresis - value, reported as a absolute temperature, NOT a delta from - the max value. - First two values are read/write and third is read only. - -vid 1 CPU core voltage. - Read only. - Floating point X.XX or X.XXX corresponding to CPU core voltage - as told to the sensor chip. Not always correct. - -vrm 1 Voltage Regulator Module version number. - "Floating point" X.X. Default 8.2. - Affects the way the driver calculates the core voltage from - the vid pins. See doc/vid for details. diff --git a/doc/developers/release_checklist b/doc/developers/release_checklist index 5f21f13e..33efc2d0 100644 --- a/doc/developers/release_checklist +++ b/doc/developers/release_checklist @@ -2,18 +2,16 @@ CHECKLIST FOR NEW RELEASES ========================== Release steps: -- Check out i2c and lm-sensors +- Check out lm-sensors - Update if necessary, the version number of libsensors (edit lib/Module.mk and change LIBMAINVER and/or LIBMINORVER) Remember: update main number when interface changes, minor if new functionality is added, and patch if only bugs are fixed. `svn diff -r Vx-y-z lib' is your friend. -- Update both CHANGES files (add the release date) -- Verify i2c dependency instructions in README, QUICKSTART, and INSTALL, - update if necessary +- Update the CHANGES file (add the release date) - Update lm_sensors.lsm and send it to the LSM by mailing it to lsm@execpc.com with the subject `add' (no quotes). -- Update lm_sensors2/version.h and i2c/kernel/i2c.h +- Update version.h - Commit - Tag the release using SVN: svn copy http://lm-sensors.org/svn/lm-sensors/trunk \ @@ -21,9 +19,9 @@ Release steps: -m "Create tag 'V2-x-x'." - Remove empty directories (e.g. rmdir `find . -type d`) - Remove 'SVN' related files/directories (e.g. rm -fR `find . -name .svn`) -- Rename i2c and lm_sensors2 to i2c-#.#.# and lm_sensors-#.#.# +- Rename lm_sensors2 to lm_sensors-#.#.# - Tar it up and post it (sign it) -- Make sure the file permissions on both the archives and the signatures +- Make sure the file permissions on both the archive and the signature are correct (664) After release, remember to: diff --git a/doc/developers/sysctl b/doc/developers/sysctl deleted file mode 100644 index 4c6532f2..00000000 --- a/doc/developers/sysctl +++ /dev/null @@ -1,16 +0,0 @@ -You can access everything under /proc/sys through the sysctl interface. This -is mostly useful for C programs, which can use the sysctl function. Try -'man 2 sysctl' for more information. - -As each chip gets its own directory under /proc/sys/dev/sensors, you must -somehow know the sysctl id of these directories to access the sensor data. -This is done through the file /proc/sys/dev/sensors/chips (see sensors.h -for the corresponding SYSCTL ids). You can only read this file; it -returns an array of struct sensors_chips_data, as defined in sensors.h. -Each chip will have its own entry here, with both its sysctl id and -the corresponding /proc name. - -Generally, it is a better idea to use the new libsensors to access this -data. If you feel you need more than the library offers, please mail us, -so we can either add the new functionality to the library, or explain how -you can work around it. diff --git a/doc/kernel/file_operations b/doc/kernel/file_operations deleted file mode 100644 index cfd9445b..00000000 --- a/doc/kernel/file_operations +++ /dev/null @@ -1,91 +0,0 @@ -This file documents the changes in struct file_operations throughout the 2.1 -kernel series. - -Kernels 2.0.x: - -struct file_operations { - int (*lseek) (struct inode *, struct file *, off_t, int); - int (*read) (struct inode *, struct file *, char *, int); - int (*write) (struct inode *, struct file *, const char *, int); - int (*readdir) (struct inode *, struct file *, void *, filldir_t); - int (*select) (struct inode *, struct file *, int, select_table *); - int (*ioctl) (struct inode *, struct file *, unsigned int, - unsigned long); - int (*mmap) (struct inode *, struct file *, struct vm_area_struct *); - int (*open) (struct inode *, struct file *); - void (*release) (struct inode *, struct file *); - int (*fsync) (struct inode *, struct file *); - int (*fasync) (struct inode *, struct file *, int); - int (*check_media_change) (kdev_t dev); - int (*revalidate) (kdev_t dev); -}; - - -Kernel 2.1.0: - -- int (*lseek) (struct inode *, struct file *, off_t, int); -+ long long (*llseek) (struct inode *, struct file *, long long, int); -- int (*read) (struct inode *, struct file *, char *, int); -+ long (*read) (struct inode *, struct file *, char *, unsigned long); -- int (*write) (struct inode *, struct file *, const char *, int); -+ long (*write) (struct inode *, struct file *, const char *, unsigned lon - - -Kernel 2.1.23: - -- int (*select) (struct inode *, struct file *, int, select_table *); -+ unsigned int (*poll) (struct file *, poll_table *); -[The lock field is added behind the revalidate field] -+ int (*lock) (struct inode *, struct file *, int, struct file_lock *); - - -Kernel 2.1.31: - -- void (*release) (struct inode *, struct file *); -+ int (*release) (struct inode *, struct file *); - - -Kernel 2.1.55: - -- int (*readdir) (struct inode *, struct file *, void *, filldir_t); -+ int (*readdir) (struct file *, void *, filldir_t); - - -Kernel 2.1.56: - -- long long (*llseek) (struct inode *, struct file *, long long, int); -+ long long (*llseek) (struct file *, long long, int); -- int (*mmap) (struct inode *, struct file *, struct vm_area_struct *); -+ int (*mmap) (struct file *, struct vm_area_struct *); -- int (*fsync) (struct inode *, struct file *); -+ int (*fsync) (struct file *, struct dentry *); -- int (*fasync) (struct inode *, struct file *, int); -+ int (*fasync) (struct file *, int); -- int (*lock) (struct inode *, struct file *, int, struct file_lock *); -+ int (*lock) (struct file *, int, struct file_lock *); - - -Kernel 2.1.70: - -- long long (*llseek) (struct file *, long long, int); -+ loff_t (*llseek) (struct file *, loff_t, int); -- long (*read) (struct inode *, struct file *, char *, unsigned long); -+ ssize_t (*read) (struct file *, char *, size_t, loff_t *); -- long (*write) (struct inode *, struct file *, const char *, - unsigned long); -+ ssize_t (*write) (struct file *, const char *, size_t, loff_t *); - - -Kernel 2.1.72: - -- unsigned int (*poll) (struct file *, poll_table *); -+ unsigned int (*poll) (struct file *, struct poll_table_struct *); - - -Kernel 2.1.118: - -[The flush field is added behind the open field -- stupid...] -+ int (*flush) (struct file *); - - -Last kernel checked: 2.2.0-pre4. diff --git a/doc/kernel/proc_dir_entry b/doc/kernel/proc_dir_entry deleted file mode 100644 index 9763d15e..00000000 --- a/doc/kernel/proc_dir_entry +++ /dev/null @@ -1,145 +0,0 @@ -This file documents how to handle the callback function that returns the -information displayed in a (non-/proc/sys) /proc file. - -For kernels before 2.1.29, you have to declare a proc_dir_entry, with -in the get_info field the procedure handler. For kernels 2.1.29 and later, -you can use the create_proc_entry function and assign a new value (the -procedure handler address) to the read_proc field: - - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29) - static int read_bus_i2c(char *buf, char **start, off_t offset, int len, - int unused); - static struct proc_dir_entry proc_bus_i2c_dir = - { - /* low_ino */ 0, /* Set by proc_register_dynamic */ - /* namelen */ 3, /* The length of the name field */ - /* name */ "i2c", - /* mode */ S_IRUGO | S_IFREG, - /* nlink */ 1, - /* uid */ 0, - /* gid */ 0, - /* size */ 0, - /* ops */ NULL, - /* get_info */ &read_bus_i2c - }; - -#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29) - static int read_bus_i2c(char *buf, char **start, off_t offset, int len, - int *eof , void *private); -#endif - - - /* This code fragment is part of the initialization code. You should do - several safety checks, like whether create_proc_entry does not return - NULL. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29) - proc_register_dynamic(&proc_root, &proc_bus_i2c_dir); -#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29) - proc_bus_i2c = create_proc_entry("i2c",0,proc_root); - proc_bus_i2c->read_proc = &read_bus_i2c; -#endif - - - -Now for the function itself. - - LINUX KERNEL 2.0.x, and 2.1.x upto 2.1.28 - ========================================= - This function is known as the get_info function. - - int get_info(char *buf, char **start, off_t offset, int len, int unused); - - (INPUT) - buf: A kernel-space buffer where we can put the information. - len: The buffer length (we have a bit of slack here: if we write - 'a little' beyond this, things will still work out) - (OUTPUT) - *buf: The complete contents of the /proc file, starting at the - beginning. - return value: the number of chars written to buf. - - This is all you have to do if all information fits in the buffer (it is - about 3K in length). You can safely ignore offset and start in this case. - - If your /proc entry gets larger, you have to do a bit more work. - - (INPUT) - buf: See above - len: see above - offset: The offset from the beginning of the /proc file where the user - wants to start reading - (OUTPUT) - *buf: A part of the /proc file. The requested information does not - have to start at the beginning. - start: this is the place within buf where the information starts (ie. - you must use offset to compute this!). - return value: The number of valid characters written to buf. Begin - counting at start, not at buf! - - You do not have to worry about not the whole information being in buf. - Another call will be done (with a higher offset value) if more is - needed. - - - LINUX KERNEL 2.1.x, from 2.1.29 upwards - ======================================= - - This function is known as the read_proc function. - - int read_proc(char *buf, char **start, off_t offset, int len, int *eof, - void *private); - (INPUT) - buf: A kernel-space buffer where we can put the information. - len: The buffer length (we have a bit of slack here: if we write - 'a little' beyond this, things will still work out) - (OUTPUT) - *buf: The complete contents of the /proc file, starting at the - beginning. - eof: You can set this to true (anything but 0) to indicate we have - reached the end of the file with this read. Not strictly - necessary, but it is more efficient (else this function may be - called again). - return value: The number of valid characters written to buf. Begin - counting at start, not at buf! - - If your /proc entry gets larger, you have to do a bit more work. - - (INPUT) - buf: See above - len: See above - offset: The offset from the beginning of the /proc file where the user - wants to start reading - (OUTPUT) - *buf: A part of the /proc file. The requested information does not - have to start at the beginning. - eof: See above - start: this is the place within buf where the information starts (ie. - you must use offset to compute this!). - return value: The number of valid characters written to buf. - - You do not have to worry about not the whole information being in buf. - Another call will be done (with a higher offset value) if more is - needed. Ignore private. - - A third way to do this: - - (INPUT) - buf: See above - len: See above - offset: The offset from the beginning of the /proc file where the user - wants to start reading - (OUTPUT) - *buf: A part of the /proc file, with the requested information starting - at the beginning. - eof: See above - start: (long)start is added to the offset pointer after reading. This - allows you to play tricks with the file offset, independent of - the number of read bytes. - return value: the number of chars written to buf. - - -This document was written by Frodo Looijaard . I do not -accept any responsibility for omissions or errors, but you are free to -drop me a note if something is wrong or if you miss something. diff --git a/doc/modules b/doc/modules deleted file mode 100644 index fd685dd1..00000000 --- a/doc/modules +++ /dev/null @@ -1,14 +0,0 @@ -Installing Modules -================== - -'make install' will install the kernel modules in the -subdirectory /lib/modules/$version/kernel/drivers/i2c/chips. -This puts the modules in the same location as a kernel -'make modules_install' does so that there will be no duplicate modules. - -If 'make install' fails, particularly on Mandrake kernels, -see FAQ #3.8 (fix MODPREF in the Makefile) and #3.9. - -For details on options that apply to most modules, see -doc/chips/MODPARMS. For details on options specific to particular -modules, see the documentation in doc/chips/. diff --git a/etc/sensors.conf.eg b/etc/sensors.conf.eg index ff89cfd7..1f616ee7 100644 --- a/etc/sensors.conf.eg +++ b/etc/sensors.conf.eg @@ -920,11 +920,6 @@ chip "as99127f-*" chip "gl518sm-*" # IMPORTANT: in0, in1, and in2 values (+5, +3, and +12) CANNOT be read -# unless you use the slow 'iterate' method. Limits will still -# work even when iterate=0. See doc/chips/gl518sm. -# Note that the 'iterate' method was trimmed while porting the -# driver to Linux 2.6 as we considered it too ugly for the thin -# benefit. # # Factors and labels taken from GL518SM datasheet, they seem to give # reasonable values with EISCA connected Fan78 @@ -1854,13 +1849,14 @@ chip "fscher-*" label in2 "Battery" # Compute Voltages using mainboard dependant MRO-values -# (see doc/chips/fscher) +# (see the fscher driver documentation in the kernel tree) # M R O O M R compute in0 (@ * (49 * 33) / 255) + (0 / 100), (@ - (0 / 100)) * 255 / (49 * 33) compute in1 (@ * (20 * 33) / 255) + (0 / 100), (@ - (0 / 100)) * 255 / (20 * 33) compute in2 (@ * (10 * 33) / 255) + (0 / 100), (@ - (0 / 100)) * 255 / (10 * 33) -# Read documentation before enabling pwm settings (see doc/chips/fscher) +# Read documentation before enabling pwm settings +# (see the fscher driver documentation in the kernel tree) # WARNING: IMPROPER VALUES MAY DAMAGE YOUR SYSTEM DUE TO OVERHEATING! # Allow fans to turn off diff --git a/kernel/Module.mk b/kernel/Module.mk deleted file mode 100644 index 50791a44..00000000 --- a/kernel/Module.mk +++ /dev/null @@ -1,42 +0,0 @@ -# Module.mk - Makefile for a Linux module for reading sensor data. -# Copyright (c) 1998, 1999 Frodo Looijaard -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -# Note that MODULE_DIR (the directory in which this file resides) is a -# 'simply expanded variable'. That means that its value is substituted -# verbatim in the rules, until it is redefined. -MODULE_DIR := kernel -KERNELDIR := $(MODULE_DIR) - -# Regrettably, even 'simply expanded variables' will not put their currently -# defined value verbatim into the command-list of rules... -KERNELTARGETS := - -# Include all dependency files -INCLUDEFILES += $(KERNELTARGETS:.o=.d) - -all-kernel: $(KERNELTARGETS) -all :: all-kernel - -# Remove sensors.o possibly left from old versions -install-kernel: all-kernel - $(RM) $(DESTDIR)$(MODPREF)/misc/sensors.o - -install :: install-kernel - -clean-kernel: - $(RM) $(KERNELDIR)/*.o $(KERNELDIR)/*.d -clean :: clean-kernel diff --git a/kernel/chips/Module.mk b/kernel/chips/Module.mk deleted file mode 100644 index 0173a406..00000000 --- a/kernel/chips/Module.mk +++ /dev/null @@ -1,210 +0,0 @@ -# Module.mk - Makefile for a Linux module for reading sensor data. -# Copyright (c) 1998 - 2001 Frodo Looijaard -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -# Note that MODULE_DIR (the directory in which this file resides) is a -# 'simply expanded variable'. That means that its value is substituted -# verbatim in the rules, until it is redefined. -MODULE_DIR := kernel/chips -KERNELCHIPSDIR := $(MODULE_DIR) - -# Regrettably, even 'simply expanded variables' will not put their currently -# defined value verbatim into the command-list of rules... - -KERNELCHIPSTARGETS := -ifeq ($(shell if grep -q '^CONFIG_IPMI_HANDLER=' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/bmcsensors.o -endif -KERNELCHIPSTARGETS += $(MODULE_DIR)/ds1307.o -KERNELCHIPSTARGETS += $(MODULE_DIR)/ltc1710.o -KERNELCHIPSTARGETS += $(MODULE_DIR)/mic74.o -KERNELCHIPSTARGETS += $(MODULE_DIR)/saa1064.o -KERNELCHIPSTARGETS += $(MODULE_DIR)/smartbatt.o -KERNELCHIPSTARGETS += $(MODULE_DIR)/smbus-arp.o - - -ifneq ($(shell if grep -q '^CONFIG_SENSORS_ADM1021=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/adm1021.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_ADM1024=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/adm1024.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_ADM1025=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/adm1025.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_ADM1026=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/adm1026.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_ADM1031=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/adm1031.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_ADM9240=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/adm9240.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_ASB100=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/asb100.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_BT869=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/bt869.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_DDCMON=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/ddcmon.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_DS1621=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/ds1621.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_EEPROM=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/eeprom.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_F71805F=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/f71805f.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_FSCHER=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/fscher.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_FSCPOS=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/fscpos.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_FSCSCY=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/fscscy.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_GL518SM=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/gl518sm.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_GL520SM=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/gl520sm.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_IT87=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/it87.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM63=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm63.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM75=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm75.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM78=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm78.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM80=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm80.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM83=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm83.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM85=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm85.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM87=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm87.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM90=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm90.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM92=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm92.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM93=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/lm93.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_MATORB=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/matorb.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_MAX1619=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/max1619.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_MAX6650=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/max6650.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_MAXILIFE=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/maxilife.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_MTP008=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/mtp008.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_PC87360=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/pc87360.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_PCA9540=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/pca9540.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_PCF8574=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/pcf8574.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_PCF8591=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/pcf8591.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_SIS5595=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/sis5595.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_SMSC47M1=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/smsc47m1.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_THMC50=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/thmc50.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_W83781D=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/w83781d.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_VIA686A=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/via686a.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_VT1211=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/vt1211.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_VT8231=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/vt8231.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_W83792D=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/w83792d.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_W83627HF=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/w83627hf.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_W83L785TS=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/w83l785ts.o -endif -ifneq ($(shell if grep -q '^CONFIG_SENSORS_XEONTEMP=y' $(LINUX)/.config; then echo 1; fi),1) -KERNELCHIPSTARGETS += $(MODULE_DIR)/xeontemp.o -endif - -# Include all dependency files -INCLUDEFILES += $(KERNELCHIPSTARGETS:.o=.d) - -all-kernel-chips: $(KERNELCHIPSTARGETS) -all :: all-kernel-chips - -# -# If $MODPREF/kernel exists, we presume the new (2.4.0) /lib/modules/x.y.z directory -# layout, so we install in kernel/drivers/i2c/chips/ and remove old versions in misc/ -# and kernel/drivers/sensors/ . Otherwise we install in misc/ as before. -# -install-kernel-chips: all-kernel-chips - if [ -n "$(KERNELCHIPSTARGETS)" ] ; then \ - $(MKDIR) $(DESTDIR)$(MODPREF)/kernel/drivers/i2c/chips ; \ - $(INSTALL) -m 644 $(KERNELCHIPSTARGETS) $(DESTDIR)$(MODPREF)/kernel/drivers/i2c/chips ; \ - for i in $(KERNELCHIPSTARGETS) ; do \ - $(RM) $(DESTDIR)$(MODPREF)/misc/`basename $$i` $(DESTDIR)$(MODPREF)/kernel/drivers/sensors/`basename $$i` \ - $(DESTDIR)$(MODPREF)/kernel/drivers/sensors/`basename $$i`.gz $(DESTDIR)$(MODPREF)/kernel/drivers/chips/`basename $$i`.gz ; \ - done ; \ - $(RMDIR) $(DESTDIR)$(MODPREF)/misc $(DESTDIR)$(MODPREF)/kernel/drivers/sensors 2> /dev/null || true ; \ - fi - -install :: install-kernel-chips - -clean-kernel-chips: - $(RM) $(KERNELCHIPSDIR)/*.o $(KERNELCHIPSDIR)/*.d -clean :: clean-kernel-chips diff --git a/kernel/chips/adm1021.c b/kernel/chips/adm1021.c deleted file mode 100644 index c1ecf1ba..00000000 --- a/kernel/chips/adm1021.c +++ /dev/null @@ -1,587 +0,0 @@ -/* - adm1021.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard and - Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x18, 0x1a, 0x29, 0x2b, - 0x4c, 0x4e, SENSORS_I2C_END -}; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066); - -/* adm1021 constants specified below */ - -/* The adm1021 registers */ -/* Read-only */ -#define ADM1021_REG_TEMP 0x00 -#define ADM1021_REG_REMOTE_TEMP 0x01 -#define ADM1021_REG_STATUS 0x02 -#define ADM1021_REG_MAN_ID 0x0FE /* 0x41 = Analog Devices, 0x49 = TI, - 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/ -#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 = 0x0X, ADM1021A/ADM1023 = 0x3X */ -#define ADM1021_REG_DIE_CODE 0x0FF /* MAX1617A */ -/* These use different addresses for reading/writing */ -#define ADM1021_REG_CONFIG_R 0x03 -#define ADM1021_REG_CONFIG_W 0x09 -#define ADM1021_REG_CONV_RATE_R 0x04 -#define ADM1021_REG_CONV_RATE_W 0x0A -/* These are for the ADM1023's additional precision on the remote temp sensor */ -#define ADM1021_REG_REM_TEMP_PREC 0x010 -#define ADM1021_REG_REM_OFFSET 0x011 -#define ADM1021_REG_REM_OFFSET_PREC 0x012 -#define ADM1021_REG_REM_TOS_PREC 0x013 -#define ADM1021_REG_REM_THYST_PREC 0x014 -/* limits */ -#define ADM1021_REG_TOS_R 0x05 -#define ADM1021_REG_TOS_W 0x0B -#define ADM1021_REG_REMOTE_TOS_R 0x07 -#define ADM1021_REG_REMOTE_TOS_W 0x0D -#define ADM1021_REG_THYST_R 0x06 -#define ADM1021_REG_THYST_W 0x0C -#define ADM1021_REG_REMOTE_THYST_R 0x08 -#define ADM1021_REG_REMOTE_THYST_W 0x0E -/* write-only */ -#define ADM1021_REG_ONESHOT 0x0F - -#define ADM1021_ALARM_TEMP (ADM1021_ALARM_TEMP_HIGH | ADM1021_ALARM_TEMP_LOW) -#define ADM1021_ALARM_RTEMP (ADM1021_ALARM_RTEMP_HIGH | ADM1021_ALARM_RTEMP_LOW\ - | ADM1021_ALARM_RTEMP_NA) -#define ADM1021_ALARM_ALL (ADM1021_ALARM_TEMP | ADM1021_ALARM_RTEMP) - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -/* Conversions note: 1021 uses normal integer signed-byte format*/ -#define TEMP_FROM_REG(val) (val > 127 ? val-256 : val) -#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? val+256 : val),0,255)) - -/* Each client has this additional data */ -struct adm1021_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 temp, temp_os, temp_hyst; /* Register values */ - u8 remote_temp, remote_temp_os, remote_temp_hyst, alarms, die_code; - u8 fail; - /* Special values for ADM1023 only */ - u8 remote_temp_prec, remote_temp_os_prec, remote_temp_hyst_prec, - remote_temp_offset, remote_temp_offset_prec; -}; - -static int adm1021_attach_adapter(struct i2c_adapter *adapter); -static int adm1021_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void adm1021_init_client(struct i2c_client *client); -static int adm1021_detach_client(struct i2c_client *client); -static int adm1021_read_value(struct i2c_client *client, u8 reg); -static int adm1021_rd_good(u8 *val, struct i2c_client *client, u8 reg, u8 mask); -static int adm1021_write_value(struct i2c_client *client, u8 reg, - u16 value); -static void adm1021_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1021_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, - long *results); -static void adm1021_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1021_die_code(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1021_update_client(struct i2c_client *client); - -/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */ -static int read_only = 0; - - -/* This is the driver that will be inserted */ -static struct i2c_driver adm1021_driver = { - .name = "ADM1021, MAX1617 sensor driver", - .id = I2C_DRIVERID_ADM1021, - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm1021_attach_adapter, - .detach_client = adm1021_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define ADM1021_SYSCTL_TEMP 1200 -#define ADM1021_SYSCTL_REMOTE_TEMP 1201 -#define ADM1021_SYSCTL_DIE_CODE 1202 -#define ADM1021_SYSCTL_ALARMS 1203 - -#define ADM1021_ALARM_TEMP_HIGH 0x40 -#define ADM1021_ALARM_TEMP_LOW 0x20 -#define ADM1021_ALARM_RTEMP_HIGH 0x10 -#define ADM1021_ALARM_RTEMP_LOW 0x08 -#define ADM1021_ALARM_RTEMP_NA 0x04 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected adm1021. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table adm1021_dir_table_template[] = { - {ADM1021_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_temp}, - {ADM1021_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_remote_temp}, - {ADM1021_SYSCTL_DIE_CODE, "die_code", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_die_code}, - {ADM1021_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_alarms}, - {0} -}; - -static ctl_table adm1021_max_dir_table_template[] = { - {ADM1021_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_temp}, - {ADM1021_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_remote_temp}, - {ADM1021_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_alarms}, - {0} -}; - -static int adm1021_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, adm1021_detect); -} - -static int adm1021_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct adm1021_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("adm1021.o: adm1021_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto error0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access adm1021_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct adm1021_data), GFP_KERNEL))) { - err = -ENOMEM; - goto error0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &adm1021_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if ((adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0x03) != 0x00 - || (adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x3F) != 0x00 - || (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) & 0xF8) != 0x00) - goto error1; - } - - /* Determine the chip type. */ - - if (kind <= 0) { - i = adm1021_read_value(new_client, ADM1021_REG_MAN_ID); - if (i == 0x41) - if ((adm1021_read_value (new_client, ADM1021_REG_DEV_ID) & 0xF0) == 0x30) - kind = adm1023; - else - kind = adm1021; - else if (i == 0x49) - kind = thmc10; - else if (i == 0x23) - kind = gl523sm; - else if ((i == 0x4d) && - (adm1021_read_value - (new_client, ADM1021_REG_DEV_ID) == 0x01)) - kind = max1617a; - else if (i == 0x54) - kind = mc1066; - /* LM84 Mfr ID in a different place, and it has more unused bits */ - else if (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) == 0x00 - && (kind == 0 /* skip extra detection */ - || ((adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x7F) == 0x00 - && (adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0xAB) == 0x00))) - kind = lm84; - else - kind = max1617; - } - - if (kind == max1617) { - type_name = "max1617"; - client_name = "MAX1617 chip"; - } else if (kind == max1617a) { - type_name = "max1617a"; - client_name = "MAX1617A chip"; - } else if (kind == adm1021) { - type_name = "adm1021"; - client_name = "ADM1021 chip"; - } else if (kind == adm1023) { - type_name = "adm1023"; - client_name = "ADM1023 chip"; - } else if (kind == thmc10) { - type_name = "thmc10"; - client_name = "THMC10 chip"; - } else if (kind == lm84) { - type_name = "lm84"; - client_name = "LM84 chip"; - } else if (kind == gl523sm) { - type_name = "gl523sm"; - client_name = "GL523SM chip"; - } else if (kind == mc1066) { - type_name = "mc1066"; - client_name = "MC1066 chip"; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto error3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - data->type == adm1021 ? adm1021_dir_table_template : - adm1021_max_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto error4; - } - data->sysctl_id = i; - - /* Initialize the ADM1021 chip */ - if (kind != lm84) - adm1021_init_client(new_client); - return 0; - - error4: - i2c_detach_client(new_client); - error3: - error1: - kfree(data); - error0: - return err; -} - -static void adm1021_init_client(struct i2c_client *client) -{ - /* Enable ADC and disable suspend mode */ - adm1021_write_value(client, ADM1021_REG_CONFIG_W, - adm1021_read_value(client, ADM1021_REG_CONFIG_R) & 0xBF); - /* Set Conversion rate to 1/sec (this can be tinkered with) */ - adm1021_write_value(client, ADM1021_REG_CONV_RATE_W, 0x04); -} - -static int adm1021_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct adm1021_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("adm1021.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - - -/* All registers are byte-sized */ -static int adm1021_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -/* only update value if read succeeded; set fail bit if failed */ -static int adm1021_rd_good(u8 *val, struct i2c_client *client, u8 reg, u8 mask) -{ - int i; - struct adm1021_data *data = client->data; - - i = i2c_smbus_read_byte_data(client, reg); - if (i < 0) { - data->fail |= mask; - return i; - } - *val = i; - return 0; -} - -static int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (read_only > 0) - return 0; - - return i2c_smbus_write_byte_data(client, reg, value); -} - -static void adm1021_update_client(struct i2c_client *client) -{ - struct adm1021_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting adm1021 update\n"); -#endif - - data->fail = 0; - adm1021_rd_good(&(data->temp), client, ADM1021_REG_TEMP, - ADM1021_ALARM_TEMP); - adm1021_rd_good(&(data->temp_os), client, ADM1021_REG_TOS_R, - ADM1021_ALARM_TEMP); - adm1021_rd_good(&(data->temp_hyst), client, - ADM1021_REG_THYST_R, ADM1021_ALARM_TEMP); - adm1021_rd_good(&(data->remote_temp), client, - ADM1021_REG_REMOTE_TEMP, ADM1021_ALARM_RTEMP); - adm1021_rd_good(&(data->remote_temp_os), client, - ADM1021_REG_REMOTE_TOS_R, ADM1021_ALARM_RTEMP); - adm1021_rd_good(&(data->remote_temp_hyst), client, - ADM1021_REG_REMOTE_THYST_R, - ADM1021_ALARM_RTEMP); - data->alarms = ADM1021_ALARM_ALL; - if (!adm1021_rd_good(&(data->alarms), client, - ADM1021_REG_STATUS, 0)) - data->alarms &= ADM1021_ALARM_ALL; - if (data->type == adm1021) - adm1021_rd_good(&(data->die_code), client, - ADM1021_REG_DIE_CODE, 0); - if (data->type == adm1023) { - adm1021_rd_good(&(data->remote_temp_prec), client, - ADM1021_REG_REM_TEMP_PREC, - ADM1021_ALARM_TEMP); - adm1021_rd_good(&(data->remote_temp_os_prec), client, - ADM1021_REG_REM_TOS_PREC, - ADM1021_ALARM_RTEMP); - adm1021_rd_good(&(data->remote_temp_hyst_prec), client, - ADM1021_REG_REM_THYST_PREC, - ADM1021_ALARM_RTEMP); - adm1021_rd_good(&(data->remote_temp_offset), client, - ADM1021_REG_REM_OFFSET, - ADM1021_ALARM_RTEMP); - adm1021_rd_good(&(data->remote_temp_offset_prec), - client, ADM1021_REG_REM_OFFSET_PREC, - ADM1021_ALARM_RTEMP); - } - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void adm1021_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1021_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1021_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_os); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_os = TEMP_TO_REG(results[0]); - adm1021_write_value(client, ADM1021_REG_TOS_W, - data->temp_os); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - adm1021_write_value(client, ADM1021_REG_THYST_W, - data->temp_hyst); - } - } -} - -void adm1021_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm1021_data *data = client->data; - int prec = 0; - - if (operation == SENSORS_PROC_REAL_INFO) - if (data->type == adm1023) { *nrels_mag = 3; } - else { *nrels_mag = 0; } - else if (operation == SENSORS_PROC_REAL_READ) { - adm1021_update_client(client); - results[0] = TEMP_FROM_REG(data->remote_temp_os); - results[1] = TEMP_FROM_REG(data->remote_temp_hyst); - results[2] = TEMP_FROM_REG(data->remote_temp); - if (data->type == adm1023) { - results[0]=results[0]*1000 + - ((data->remote_temp_os_prec >> 5) * 125); - results[1]=results[1]*1000 + - ((data->remote_temp_hyst_prec >> 5) * 125); - results[2]=(TEMP_FROM_REG(data->remote_temp_offset)*1000) + - ((data->remote_temp_offset_prec >> 5) * 125); - results[3]=TEMP_FROM_REG(data->remote_temp)*1000 + - ((data->remote_temp_prec >> 5) * 125); - *nrels_mag = 4; - } else { - *nrels_mag = 3; - } - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (data->type == adm1023) { - prec=((results[0]-((results[0]/1000)*1000))/125)<<5; - adm1021_write_value(client, - ADM1021_REG_REM_TOS_PREC, - prec); - results[0]=results[0]/1000; - data->remote_temp_os_prec=prec; - } - data->remote_temp_os = TEMP_TO_REG(results[0]); - adm1021_write_value(client, - ADM1021_REG_REMOTE_TOS_W, - data->remote_temp_os); - } - if (*nrels_mag >= 2) { - if (data->type == adm1023) { - prec=((results[1]-((results[1]/1000)*1000))/125)<<5; - adm1021_write_value(client, - ADM1021_REG_REM_THYST_PREC, - prec); - results[1]=results[1]/1000; - data->remote_temp_hyst_prec=prec; - } - data->remote_temp_hyst = TEMP_TO_REG(results[1]); - adm1021_write_value(client, - ADM1021_REG_REMOTE_THYST_W, - data->remote_temp_hyst); - } - if (*nrels_mag >= 3) { - if (data->type == adm1023) { - prec=((results[2]-((results[2]/1000)*1000))/125)<<5; - adm1021_write_value(client, - ADM1021_REG_REM_OFFSET_PREC, - prec); - results[2]=results[2]/1000; - data->remote_temp_offset_prec=prec; - data->remote_temp_offset=results[2]; - adm1021_write_value(client, - ADM1021_REG_REM_OFFSET, - data->remote_temp_offset); - } - } - } -} - -void adm1021_die_code(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm1021_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1021_update_client(client); - results[0] = data->die_code; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - /* Can't write to it */ - } -} - -void adm1021_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1021_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1021_update_client(client); - results[0] = data->alarms | data->fail; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - /* Can't write to it */ - } -} - -static int __init sm_adm1021_init(void) -{ - printk(KERN_INFO "adm1021.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&adm1021_driver); -} - -static void __exit sm_adm1021_exit(void) -{ - i2c_del_driver(&adm1021_driver); -} - -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("adm1021 driver"); -MODULE_LICENSE("GPL"); - -MODULE_PARM(read_only, "i"); -MODULE_PARM_DESC(read_only, "Don't set any values, read only mode"); - -module_init(sm_adm1021_init) -module_exit(sm_adm1021_exit) diff --git a/kernel/chips/adm1024.c b/kernel/chips/adm1024.c deleted file mode 100644 index 18ff22c7..00000000 --- a/kernel/chips/adm1024.c +++ /dev/null @@ -1,776 +0,0 @@ -/* - adm1024.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Add by Ken Bowley from the adm1025.c written by - Gordon Wu and from adm9240.c written by - Copyright (c) 1999 Frodo Looijaard - and Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* Supports the Analog Devices ADM1024. See doc/chips/adm1024 for details */ - -#include -#include -#include -#include -#include -#include "version.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(adm1024); - -/* Many ADM1024 constants specified below */ - -#define ADM1024_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define ADM1024_REG_IN_MIN(nr) (0x2c + (nr) * 2) -#define ADM1024_REG_IN(nr) (0x20 + (nr)) - -/* The ADM1024 registers */ -#define ADM1024_REG_INT_TEMP_TRIP_SET 0x13 -#define ADM1024_REG_EXT_TEMP_TRIP_SET 0x14 -#define ADM1024_REG_TEST 0x15 -#define ADM1024_REG_CHANNEL_MODE 0x16 -#define ADM1024_REG_INT_TEMP_TRIP 0x17 /* read only */ -#define ADM1024_REG_EXT_TEMP_TRIP 0x18 /* read only */ -#define ADM1024_REG_ANALOG_OUT 0x19 -#define ADM1024_REG_AIN1_LOW_LIMIT 0x1A -#define ADM1024_REG_AIN2_LOW_LIMIT 0x1B -/* These are all read-only */ -#define ADM1024_REG_2_5V 0x20 /* 2.5V Measured Value/EXT Temp 2 */ -#define ADM1024_REG_VCCP1 0x21 -#define ADM1024_REG_3_3V 0x22 /* VCC Measured Value */ -#define ADM1024_REG_5V 0x23 -#define ADM1024_REG_12V 0x24 -#define ADM1024_REG_VCCP2 0x25 -#define ADM1024_REG_EXT_TEMP1 0x26 -#define ADM1024_REG_TEMP 0x27 -#define ADM1024_REG_FAN1 0x28 /* FAN1/AIN1 Value */ -#define ADM1024_REG_FAN2 0x29 /* FAN2/AIN2 Value */ -#define ADM1024_REG_COMPANY_ID 0x3E /* 0x41 for ADM1024 */ -#define ADM1024_REG_DIE_REV 0x3F -/* These are read/write */ -#define ADM1024_REG_2_5V_HIGH 0x2B /* 2.5V/Ext Temp2 High Limit */ -#define ADM1024_REG_2_5V_LOW 0x2C /* 2.5V/Ext Temp2 Low Limit */ -#define ADM1024_REG_VCCP1_HIGH 0x2D -#define ADM1024_REG_VCCP1_LOW 0x2E -#define ADM1024_REG_3_3V_HIGH 0x2F /* VCC High Limit */ -#define ADM1024_REG_3_3V_LOW 0x30 /* VCC Low Limit */ -#define ADM1024_REG_5V_HIGH 0x31 -#define ADM1024_REG_5V_LOW 0x32 -#define ADM1024_REG_12V_HIGH 0x33 -#define ADM1024_REG_12V_LOW 0x34 -#define ADM1024_REG_VCCP2_HIGH 0x35 -#define ADM1024_REG_VCCP2_LOW 0x36 -#define ADM1024_REG_EXT_TEMP1_HIGH 0x37 -#define ADM1024_REG_EXT_TEMP1_LOW 0x38 -#define ADM1024_REG_TOS 0x39 -#define ADM1024_REG_THYST 0x3A -#define ADM1024_REG_FAN1_MIN 0x3B -#define ADM1024_REG_FAN2_MIN 0x3C - -#define ADM1024_REG_CONFIG 0x40 -#define ADM1024_REG_INT1_STAT 0x41 -#define ADM1024_REG_INT2_STAT 0x42 -#define ADM1024_REG_INT1_MASK 0x43 -#define ADM1024_REG_INT2_MASK 0x44 - -#define ADM1024_REG_CHASSIS_CLEAR 0x46 -#define ADM1024_REG_VID_FAN_DIV 0x47 -#define ADM1024_REG_I2C_ADDR 0x48 -#define ADM1024_REG_VID4 0x49 -#define ADM1024_REG_CONFIG2 0x4A -#define ADM1024_REG_TEMP_CONFIG 0x4B -#define ADM1024_REG_EXTMODE1 0x4C /* Interupt Status Register Mirror No. 1 */ -#define ADM1024_REG_EXTMODE2 0x4D /* Interupt Status Register Mirror No. 2 */ - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val,nr) (SENSORS_LIMIT(((val) & 0xff),0,255)) -#define IN_FROM_REG(val,nr) (val) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:\ - (val)==255?0:1350000/((div)*(val))) - -#define TEMP_FROM_REG(temp) \ - ((temp)<256?((((temp)&0x1fe) >> 1) * 10) + ((temp) & 1) * 5: \ - ((((temp)&0x1fe) >> 1) -255) * 10 - ((temp) & 1) * 5) \ - -#define EXT_TEMP_FROM_REG(temp) (((temp)>0x80?(temp)-0x100:(temp))*10) - - -#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10) - -#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT(((val)<0?(((val)-5)/10):\ - ((val)+5)/10), \ - 0,255) - -#define ALARMS_FROM_REG(val) (val) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==1?0:((val)==8?3:((val)==4?2:1))) - -#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ - 205-(val)*5) - -/* For each registered ADM1024, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new adm1024 client is - allocated. */ -struct adm1024_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[6]; /* Register value */ - u8 in_max[6]; /* Register value */ - u8 in_min[6]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - int temp; /* Temp, shifted right */ - u8 temp_os_max; /* Register value */ - u8 temp_os_hyst; /* Register value */ - int temp1; /* Ext Temp 1 */ - u8 temp1_os_max; - u8 temp1_os_hyst; - int temp2; /* Ext Temp 2 */ - u8 temp2_os_max; - u8 temp2_os_hyst; - u16 alarms; /* Register encoding, combined */ - u8 analog_out; /* Register value */ - u8 vid; /* Register value combined */ -}; - - - -static int adm1024_attach_adapter(struct i2c_adapter *adapter); -static int adm1024_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int adm1024_detach_client(struct i2c_client *client); - -static int adm1024_read_value(struct i2c_client *client, u8 register); -static int adm1024_write_value(struct i2c_client *client, u8 register, - u8 value); -static void adm1024_update_client(struct i2c_client *client); -static void adm1024_init_client(struct i2c_client *client); - - -static void adm1024_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1024_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1024_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1024_temp1(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1024_temp2(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1024_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1024_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1024_analog_out(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, - long *results); -static void adm1024_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver adm1024_driver = { - .name = "ADM1024 sensor driver", - .id = I2C_DRIVERID_ADM1024, - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm1024_attach_adapter, - .detach_client = adm1024_detach_client, -}; - -/* The /proc/sys entries */ -/* -- SENSORS SYSCTL START -- */ - -#define ADM1024_SYSCTL_IN0 1000 /* Volts * 100 */ -#define ADM1024_SYSCTL_IN1 1001 -#define ADM1024_SYSCTL_IN2 1002 -#define ADM1024_SYSCTL_IN3 1003 -#define ADM1024_SYSCTL_IN4 1004 -#define ADM1024_SYSCTL_IN5 1005 -#define ADM1024_SYSCTL_FAN1 1101 /* Rotations/min */ -#define ADM1024_SYSCTL_FAN2 1102 -#define ADM1024_SYSCTL_TEMP 1250 /* Degrees Celsius * 100 */ -#define ADM1024_SYSCTL_TEMP1 1290 /* Degrees Celsius */ -#define ADM1024_SYSCTL_TEMP2 1295 /* Degrees Celsius */ -#define ADM1024_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define ADM1024_SYSCTL_ALARMS 2001 /* bitvector */ -#define ADM1024_SYSCTL_ANALOG_OUT 2002 -#define ADM1024_SYSCTL_VID 2003 - -#define ADM1024_ALARM_IN0 0x0001 -#define ADM1024_ALARM_IN1 0x0002 -#define ADM1024_ALARM_IN2 0x0004 -#define ADM1024_ALARM_IN3 0x0008 -#define ADM1024_ALARM_IN4 0x0100 -#define ADM1024_ALARM_IN5 0x0200 -#define ADM1024_ALARM_FAN1 0x0040 -#define ADM1024_ALARM_FAN2 0x0080 -#define ADM1024_ALARM_TEMP 0x0010 -#define ADM1024_ALARM_TEMP1 0x0020 -#define ADM1024_ALARM_TEMP2 0x0001 -#define ADM1024_ALARM_CHAS 0x1000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected ADM1024. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table adm1024_dir_table_template[] = { - {ADM1024_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_in}, - {ADM1024_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_in}, - {ADM1024_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_in}, - {ADM1024_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_in}, - {ADM1024_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_in}, - {ADM1024_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_in}, - {ADM1024_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_fan}, - {ADM1024_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_fan}, - {ADM1024_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_temp}, - {ADM1024_SYSCTL_TEMP1, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_temp1}, - {ADM1024_SYSCTL_TEMP2, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_temp2}, - {ADM1024_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_fan_div}, - {ADM1024_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_alarms}, - {ADM1024_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_analog_out}, - {ADM1024_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1024_vid}, - {0} -}; - -static int adm1024_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, adm1024_detect); -} - -static int adm1024_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct adm1024_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("adm1024.o: adm1024_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access adm1024_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct adm1024_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &adm1024_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if((adm1024_read_value(new_client, ADM1024_REG_CONFIG) & 0x80) != 0x00) - goto ERROR1; - } - - /* Determine the chip type. */ - if (kind <= 0) { - i = adm1024_read_value(new_client, ADM1024_REG_COMPANY_ID); - if (i == 0x41) - kind = adm1024; - else { - if (kind == 0) - printk - ("adm1024.o: Ignoring 'force' parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - goto ERROR1; - } - } - - if (kind == adm1024) { - type_name = "adm1024"; - client_name = "ADM1024 chip"; - } else { -#ifdef DEBUG - printk("adm1024.o: Internal error: unknown kind (%d)?!?", - kind); -#endif - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - adm1024_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the ADM1024 chip */ - adm1024_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int adm1024_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct adm1024_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("adm1024.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -static int adm1024_read_value(struct i2c_client *client, u8 reg) -{ - return 0xFF & i2c_smbus_read_byte_data(client, reg); -} - -static int adm1024_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static void adm1024_init_client(struct i2c_client *client) -{ - /* Enable temperature channel 2 */ - adm1024_write_value(client, ADM1024_REG_CHANNEL_MODE, adm1024_read_value(client, ADM1024_REG_CHANNEL_MODE) | 0x04); - - /* Start monitoring */ - adm1024_write_value(client, ADM1024_REG_CONFIG, 0x07); -} - -static void adm1024_update_client(struct i2c_client *client) -{ - struct adm1024_data *data = client->data; - u8 i; - - down(&data->update_lock); - - if ( - (jiffies - data->last_updated > - (data->type == adm1024 ? HZ / 2 : HZ * 2)) - || (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting adm1024 update\n"); -#endif - for (i = 0; i <= 5; i++) { - data->in[i] = - adm1024_read_value(client, ADM1024_REG_IN(i)); - data->in_min[i] = - adm1024_read_value(client, - ADM1024_REG_IN_MIN(i)); - data->in_max[i] = - adm1024_read_value(client, - ADM1024_REG_IN_MAX(i)); - } - data->fan[0] = - adm1024_read_value(client, ADM1024_REG_FAN1); - data->fan_min[0] = - adm1024_read_value(client, ADM1024_REG_FAN1_MIN); - data->fan[1] = - adm1024_read_value(client, ADM1024_REG_FAN2); - data->fan_min[1] = - adm1024_read_value(client, ADM1024_REG_FAN2_MIN); - data->temp = - (adm1024_read_value(client, ADM1024_REG_TEMP) << 1) + - ((adm1024_read_value - (client, ADM1024_REG_TEMP_CONFIG) & 0x80) >> 7); - data->temp_os_max = - adm1024_read_value(client, ADM1024_REG_TOS); - data->temp_os_hyst = - adm1024_read_value(client, ADM1024_REG_THYST); - data->temp1 = - adm1024_read_value(client, ADM1024_REG_EXT_TEMP1); - data->temp1_os_max = - adm1024_read_value(client, ADM1024_REG_EXT_TEMP1_HIGH); - data->temp1_os_hyst = - adm1024_read_value(client, ADM1024_REG_EXT_TEMP1_LOW); - data->temp2 = - adm1024_read_value(client, ADM1024_REG_2_5V); - data->temp2_os_max = - adm1024_read_value(client, ADM1024_REG_2_5V_HIGH); - data->temp2_os_hyst = - adm1024_read_value(client, ADM1024_REG_2_5V_LOW); - - i = adm1024_read_value(client, ADM1024_REG_VID_FAN_DIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - data->vid = i & 0x0f; - data->vid |= - (adm1024_read_value(client, ADM1024_REG_VID4) & 0x01) - << 4; - - data->alarms = - adm1024_read_value(client, - ADM1024_REG_INT1_STAT) + - (adm1024_read_value(client, ADM1024_REG_INT2_STAT) << - 8); - data->analog_out = - adm1024_read_value(client, ADM1024_REG_ANALOG_OUT); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void adm1024_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - - int scales[6] = { 250, 225, 330, 500, 1200, 270 }; - - struct adm1024_data *data = client->data; - int nr = ctl_name - ADM1024_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1024_update_client(client); - results[0] = - IN_FROM_REG(data->in_min[nr], nr) * scales[nr] / 192; - results[1] = - IN_FROM_REG(data->in_max[nr], nr) * scales[nr] / 192; - results[2] = - IN_FROM_REG(data->in[nr], nr) * scales[nr] / 192; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = - IN_TO_REG((results[0] * 192) / scales[nr], nr); - adm1024_write_value(client, ADM1024_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = - IN_TO_REG((results[1] * 192) / scales[nr], nr); - adm1024_write_value(client, ADM1024_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void adm1024_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1024_data *data = client->data; - int nr = ctl_name - ADM1024_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1024_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data-> - fan_div[nr - 1])); - results[1] = - FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = FAN_TO_REG(results[0], - DIV_FROM_REG - (data-> - fan_div[nr - - 1])); - adm1024_write_value(client, - nr == - 1 ? ADM1024_REG_FAN1_MIN : - ADM1024_REG_FAN2_MIN, - data->fan_min[nr - 1]); - } - } -} - - -void adm1024_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1024_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1024_update_client(client); - results[0] = TEMP_LIMIT_FROM_REG(data->temp_os_max); - results[1] = TEMP_LIMIT_FROM_REG(data->temp_os_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_os_max = TEMP_LIMIT_TO_REG(results[0]); - adm1024_write_value(client, ADM1024_REG_TOS, - data->temp_os_max); - } - if (*nrels_mag >= 2) { - data->temp_os_hyst = TEMP_LIMIT_TO_REG(results[1]); - adm1024_write_value(client, ADM1024_REG_THYST, - data->temp_os_hyst); - } - } -} - -void adm1024_temp1(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1024_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1024_update_client(client); - results[0] = TEMP_LIMIT_FROM_REG(data->temp1_os_max); - results[1] = TEMP_LIMIT_FROM_REG(data->temp1_os_hyst); - results[2] = EXT_TEMP_FROM_REG(data->temp1); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp1_os_max = TEMP_LIMIT_TO_REG(results[0]); - adm1024_write_value(client, ADM1024_REG_EXT_TEMP1_HIGH, - data->temp1_os_max); - } - if (*nrels_mag >= 2) { - data->temp1_os_hyst = TEMP_LIMIT_TO_REG(results[1]); - adm1024_write_value(client, ADM1024_REG_EXT_TEMP1_LOW, - data->temp1_os_hyst); - } - } -} - -void adm1024_temp2(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1024_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1024_update_client(client); - results[0] = TEMP_LIMIT_FROM_REG(data->temp2_os_max); - results[1] = TEMP_LIMIT_FROM_REG(data->temp2_os_hyst); - results[2] = EXT_TEMP_FROM_REG(data->temp2); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp2_os_max = TEMP_LIMIT_TO_REG(results[0]); - adm1024_write_value(client, ADM1024_REG_2_5V_HIGH, - data->temp2_os_max); - } - if (*nrels_mag >= 2) { - data->temp2_os_hyst = TEMP_LIMIT_TO_REG(results[1]); - adm1024_write_value(client, ADM1024_REG_2_5V_LOW, - data->temp2_os_hyst); - } - } -} - -void adm1024_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1024_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1024_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void adm1024_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm1024_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1024_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = adm1024_read_value(client, ADM1024_REG_VID_FAN_DIV); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan_div[1] << 6); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div[0] << 4); - adm1024_write_value(client, - ADM1024_REG_VID_FAN_DIV, old); - } - } -} - -void adm1024_analog_out(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm1024_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1024_update_client(client); - results[0] = data->analog_out; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->analog_out = results[0]; - adm1024_write_value(client, ADM1024_REG_ANALOG_OUT, - data->analog_out); - } - } -} - -void adm1024_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1024_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1024_update_client(client); - results[0] = VID_FROM_REG(data->vid); - *nrels_mag = 1; - } -} - -static int __init sm_adm1024_init(void) -{ - printk("adm1024.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&adm1024_driver); -} - -static void __exit sm_adm1024_exit(void) -{ - i2c_del_driver(&adm1024_driver); -} - - - -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("ADM1024 driver"); - -MODULE_LICENSE("GPL"); - -module_init(sm_adm1024_init); -module_exit(sm_adm1024_exit); diff --git a/kernel/chips/adm1025.c b/kernel/chips/adm1025.c deleted file mode 100644 index 22151e12..00000000 --- a/kernel/chips/adm1025.c +++ /dev/null @@ -1,588 +0,0 @@ -/* - adm1025.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2000 Chen-Yuan Wu - Copyright (c) 2003-2004 Jean Delvare - - Based on the adm9240 driver. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* Supports the Analog Devices ADM1025 and the Philips NE1619. - See doc/chips/adm1025 for details */ - -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_2(adm1025, ne1619); - -/* Many ADM1025 constants specified below */ - - -/* The ADM1025 registers */ - -/* These are all read-only */ -#define ADM1025_REG_2_5V 0x20 /* not used directly, see */ -#define ADM1025_REG_VCCP1 0x21 /* ADM1025_REG_IN(nr) below */ -#define ADM1025_REG_3_3V 0x22 -#define ADM1025_REG_5V 0x23 -#define ADM1025_REG_12V 0x24 -#define ADM1025_REG_VCC 0x25 - -#define ADM1025_REG_RTEMP 0x26 /* not used directly, see */ -#define ADM1025_REG_LTEMP 0x27 /* ADM1025_REG_TEMP(nr) below */ - -#define ADM1025_REG_COMPANY_ID 0x3E /* 0x41 for Analog Devices, - 0xA1 for Philips */ -#define ADM1025_REG_DIE_REV 0x3F /* 0x20-0x2F for ADM1025 and compatible */ - -#define ADM1025_REG_STATUS1 0x41 -#define ADM1025_REG_STATUS2 0x42 - -#define ADM1025_REG_VID 0x47 -#define ADM1025_REG_VID4 0x49 /* actually R/W - but we don't write to it */ - -/* These are read/write */ -#define ADM1025_REG_2_5V_HIGH 0x2B /* not used directly, see */ -#define ADM1025_REG_2_5V_LOW 0x2C /* ADM1025_REG_IN_MAX(nr) and */ -#define ADM1025_REG_VCCP1_HIGH 0x2D /* ADM1025_REG_IN_MIN(nr) below */ -#define ADM1025_REG_VCCP1_LOW 0x2E -#define ADM1025_REG_3_3V_HIGH 0x2F -#define ADM1025_REG_3_3V_LOW 0x30 -#define ADM1025_REG_5V_HIGH 0x31 -#define ADM1025_REG_5V_LOW 0x32 -#define ADM1025_REG_12V_HIGH 0x33 -#define ADM1025_REG_12V_LOW 0x34 -#define ADM1025_REG_VCC_HIGH 0x35 -#define ADM1025_REG_VCC_LOW 0x36 - -#define ADM1025_REG_RTEMP_HIGH 0x37 /* not used directly, see */ -#define ADM1025_REG_RTEMP_LOW 0x38 /* ADM1025_REG_TEMP_MAX(nr) and */ -#define ADM1025_REG_LTEMP_HIGH 0x39 /* ADM1025_REG_TEMP_MIN(nr) below */ -#define ADM1025_REG_LTEMP_LOW 0x3A - -#define ADM1025_REG_CONFIG 0x40 - -/* Useful macros */ -#define ADM1025_REG_IN(nr) (ADM1025_REG_2_5V + (nr)) -#define ADM1025_REG_IN_MAX(nr) (ADM1025_REG_2_5V_HIGH + (nr) * 2) -#define ADM1025_REG_IN_MIN(nr) (ADM1025_REG_2_5V_LOW + (nr) * 2) -#define ADM1025_REG_TEMP(nr) (ADM1025_REG_RTEMP + (nr)) -#define ADM1025_REG_TEMP_HIGH(nr) (ADM1025_REG_RTEMP_HIGH + (nr) * 2) -#define ADM1025_REG_TEMP_LOW(nr) (ADM1025_REG_RTEMP_LOW + (nr) * 2) - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val) SENSORS_LIMIT(val, 0, 255) -#define IN_FROM_REG(val) (val) - -#define TEMP_FROM_REG(val) (((val)>=0x80?(val)-0x100:(val))*10) -#define TEMP_TO_REG(val) SENSORS_LIMIT(((val)<0?(((val)-5)/10):\ - ((val)+5)/10),-128,127) - -#define ALARMS_FROM_REG(val) (val) - -/* For each registered ADM1025, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new adm1025 client is - allocated. */ -struct adm1025_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[6]; /* Register value */ - u8 in_max[6]; /* Register value */ - u8 in_min[6]; /* Register value */ - u8 temp[2]; /* Register value */ - u8 temp_high[2]; /* Register value */ - u8 temp_low[2]; /* Register value */ - u16 alarms; /* Register encoding, combined */ - u8 vid; /* Register value combined */ - u8 vrm; -}; - - -static int adm1025_attach_adapter(struct i2c_adapter *adapter); -static int adm1025_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int adm1025_detach_client(struct i2c_client *client); -static void adm1025_update_client(struct i2c_client *client); -static void adm1025_init_client(struct i2c_client *client); - - -static void adm1025_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1025_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1025_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1025_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1025_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver adm1025_driver = { - .name = "ADM1025 sensor driver", - .id = I2C_DRIVERID_ADM1025, - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm1025_attach_adapter, - .detach_client = adm1025_detach_client, -}; - -/* The /proc/sys entries */ -/* -- SENSORS SYSCTL START -- */ - -#define ADM1025_SYSCTL_IN0 1000 /* Volts * 100 */ -#define ADM1025_SYSCTL_IN1 1001 -#define ADM1025_SYSCTL_IN2 1002 -#define ADM1025_SYSCTL_IN3 1003 -#define ADM1025_SYSCTL_IN4 1004 -#define ADM1025_SYSCTL_IN5 1005 - -#define ADM1025_SYSCTL_RTEMP 1250 /* Degrees Celsius * 10 */ -#define ADM1025_SYSCTL_TEMP 1251 - -#define ADM1025_SYSCTL_ALARMS 2001 /* bitvector */ -#define ADM1025_SYSCTL_VID 2003 /* Volts * 1000 */ -#define ADM1025_SYSCTL_VRM 2004 - -#define ADM1025_ALARM_IN0 0x0001 -#define ADM1025_ALARM_IN1 0x0002 -#define ADM1025_ALARM_IN2 0x0004 -#define ADM1025_ALARM_IN3 0x0008 -#define ADM1025_ALARM_IN4 0x0100 -#define ADM1025_ALARM_IN5 0x0200 -#define ADM1025_ALARM_RTEMP 0x0020 -#define ADM1025_ALARM_TEMP 0x0010 -#define ADM1025_ALARM_RFAULT 0x4000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected ADM1025. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table adm1025_dir_table_template[] = { - {ADM1025_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_in}, - {ADM1025_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_in}, - {ADM1025_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_in}, - {ADM1025_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_in}, - {ADM1025_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_in}, - {ADM1025_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_in}, - {ADM1025_SYSCTL_RTEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_temp}, - {ADM1025_SYSCTL_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_temp}, - {ADM1025_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_alarms}, - {ADM1025_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_vid}, - {ADM1025_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1025_vrm}, - {0} -}; - -static int adm1025_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, adm1025_detect); -} - -static int adm1025_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct adm1025_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("adm1025.o: adm1025_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access adm1025_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct adm1025_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &adm1025_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if ((i2c_smbus_read_byte_data(new_client, - ADM1025_REG_CONFIG) & 0x80) != 0x00 - || (i2c_smbus_read_byte_data(new_client, - ADM1025_REG_STATUS1) & 0xC0) != 0x00 - || (i2c_smbus_read_byte_data(new_client, - ADM1025_REG_STATUS2) & 0xBC) != 0x00) - goto ERROR1; - } - - /* Determine the chip type. */ - if (kind <= 0) { - u8 man_id, chip_id; - - man_id = i2c_smbus_read_byte_data(new_client, - ADM1025_REG_COMPANY_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - ADM1025_REG_DIE_REV); - - if (man_id == 0x41) { /* Analog Devices */ - if ((chip_id & 0xF0) == 0x20) /* ADM1025 */ - kind = adm1025; - } else if (man_id == 0xA1) { /* Philips */ - if (address != 0x2E - && (chip_id & 0xF0) == 0x20) /* NE1619 */ - kind = ne1619; - } - } - - if (kind <= 0) { /* Identification failed */ - printk("adm1025.o: Unsupported chip.\n"); - goto ERROR1; - } - - if (kind == adm1025) { - type_name = "adm1025"; - client_name = "ADM1025 chip"; - } else if (kind == ne1619) { - type_name = "ne1619"; - client_name = "NE1619 chip"; - } else { -#ifdef DEBUG - printk("adm1025.o: Internal error: unknown kind (%d)?!?", - kind); -#endif - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - adm1025_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the ADM1025 chip */ - adm1025_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int adm1025_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct adm1025_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("adm1025.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -/* Called when we have found a new ADM1025. */ -static void adm1025_init_client(struct i2c_client *client) -{ - struct adm1025_data *data = client->data; - u8 reg; - int i; - - data->vrm = 82; - - /* Set high limits - Usually we avoid setting limits on driver init, but it happens - that the ADM1025 comes with stupid default limits (all registers - set to 0). In case the chip has not gone through any limit - setting yet, we better set the high limits to the max so that - no alarm triggers. */ - for (i=0; i<6; i++) { - reg = i2c_smbus_read_byte_data(client, - ADM1025_REG_IN_MAX(i)); - if (reg == 0) - i2c_smbus_write_byte_data(client, - ADM1025_REG_IN_MAX(i), - 0xFF); - } - for (i=0; i<2; i++) { - reg = i2c_smbus_read_byte_data(client, - ADM1025_REG_TEMP_HIGH(i)); - if (reg == 0) - i2c_smbus_write_byte_data(client, - ADM1025_REG_TEMP_HIGH(i), - 0x7F); - } - - /* Start monitoring */ - reg = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG); - i2c_smbus_write_byte_data(client, ADM1025_REG_CONFIG, (reg|0x01)&0x7F); -} - -static void adm1025_update_client(struct i2c_client *client) -{ - struct adm1025_data *data = client->data; - u8 nr; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 2 * HZ) - || (jiffies < data->last_updated) || !data->valid) { -#ifdef DEBUG - printk("Starting adm1025 update\n"); -#endif - - /* Voltages */ - for (nr = 0; nr < 6; nr++) { - data->in[nr] = i2c_smbus_read_byte_data(client, ADM1025_REG_IN(nr)); - data->in_min[nr] = i2c_smbus_read_byte_data(client, ADM1025_REG_IN_MIN(nr)); - data->in_max[nr] = i2c_smbus_read_byte_data(client, ADM1025_REG_IN_MAX(nr)); - } - - /* Temperatures */ - for (nr = 0; nr < 2; nr++) { - data->temp[nr] = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP(nr)); - data->temp_high[nr] = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP_HIGH(nr)); - data->temp_low[nr] = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP_LOW(nr)); - } - - /* VID */ - data->vid = (i2c_smbus_read_byte_data(client, ADM1025_REG_VID) & 0x0f) - + ((i2c_smbus_read_byte_data(client, ADM1025_REG_VID4) & 0x01) << 4); - - /* Alarms */ - data->alarms = (i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS1) & 0x3f) - + ((i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS2) & 0x43) << 8); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the data - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void adm1025_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int scales[6] = { 250, 225, 330, 500, 1200, 330 }; - - struct adm1025_data *data = client->data; - int nr = ctl_name - ADM1025_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1025_update_client(client); - results[0] = (IN_FROM_REG(data->in_min[nr]) * scales[nr] + 96) / 192; - results[1] = (IN_FROM_REG(data->in_max[nr]) * scales[nr] + 96) / 192; - results[2] = (IN_FROM_REG(data->in[nr]) * scales[nr] + 96) / 192; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG((results[0] * 192 + scales[nr] / 2) - / scales[nr]); - i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG((results[1] * 192 + scales[nr] / 2) - / scales[nr]); - i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void adm1025_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1025_data *data = client->data; - int nr = ctl_name - ADM1025_SYSCTL_RTEMP; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1025_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_high[nr]); - results[1] = TEMP_FROM_REG(data->temp_low[nr]); - results[2] = TEMP_FROM_REG(data->temp[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_high[nr] = TEMP_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(nr), - data->temp_high[nr]); - } - if (*nrels_mag >= 2) { - data->temp_low[nr] = TEMP_TO_REG(results[1]); - i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(nr), - data->temp_low[nr]); - } - } -} - -void adm1025_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1025_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1025_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void adm1025_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1025_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1025_update_client(client); - results[0] = vid_from_reg(data->vid, data->vrm); - *nrels_mag = 1; - } -} - -void adm1025_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1025_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) - data->vrm = results[0]; - } -} - -static int __init sm_adm1025_init(void) -{ - printk("adm1025.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&adm1025_driver); -} - -static void __exit sm_adm1025_exit(void) -{ - i2c_del_driver(&adm1025_driver); -} - - - -MODULE_AUTHOR("Chen-Yuan Wu " - " and Jean Delvare "); -MODULE_DESCRIPTION("ADM1025 driver"); - -module_init(sm_adm1025_init); -module_exit(sm_adm1025_exit); diff --git a/kernel/chips/adm1026.c b/kernel/chips/adm1026.c deleted file mode 100644 index 6fd62d29..00000000 --- a/kernel/chips/adm1026.c +++ /dev/null @@ -1,1741 +0,0 @@ -/* - adm1026.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2002, 2003 Philip Pokorny - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - CHANGELOG - - 2003-03-13 Initial development - 2003-05-07 First Release. Includes GPIO fixup and full - functionality. - 2003-05-18 Minor fixups and tweaks. - Print GPIO config after fixup. - Adjust fan MIN if DIV changes. - 2003-05-21 Fix printing of FAN/GPIO config - Fix silly bug in fan_div logic - Fix fan_min handling so that 0xff is 0 is 0xff - 2003-05-25 Fix more silly typos... - 2003-06-11 Change FAN_xx_REG macros to use different scaling - Most (all?) drivers assume two pulses per rev fans - and the old scaling was producing double the RPM's - Thanks to Jerome Hsiao @ Arima for pointing this out. - 2004-01-27 Remove use of temporary ID. - Define addresses as a range. -*/ - -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" - -#ifndef I2C_DRIVERID_ADM1026 -#define I2C_DRIVERID_ADM1026 1048 -#endif - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(adm1026); - -static int gpio_input[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int gpio_output[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int gpio_inverted[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int gpio_normal[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int gpio_fan[8] = { -1, -1, -1, -1, -1, -1, -1, -1 }; -MODULE_PARM(gpio_input,"1-17i"); -MODULE_PARM_DESC(gpio_input,"List of GPIO pins (0-16) to program as inputs"); -MODULE_PARM(gpio_output,"1-17i"); -MODULE_PARM_DESC(gpio_output,"List of GPIO pins (0-16) to program as outputs"); -MODULE_PARM(gpio_inverted,"1-17i"); -MODULE_PARM_DESC(gpio_inverted,"List of GPIO pins (0-16) to program as inverted"); -MODULE_PARM(gpio_normal,"1-17i"); -MODULE_PARM_DESC(gpio_normal,"List of GPIO pins (0-16) to program as normal/non-inverted"); -MODULE_PARM(gpio_fan,"1-8i"); -MODULE_PARM_DESC(gpio_fan,"List of GPIO pins (0-7) to program as fan tachs"); - -/* Many ADM1026 constants specified below */ - -/* The ADM1026 registers */ -#define ADM1026_REG_CONFIG1 (0x00) -#define CFG1_MONITOR (0x01) -#define CFG1_INT_ENABLE (0x02) -#define CFG1_INT_CLEAR (0x04) -#define CFG1_AIN8_9 (0x08) -#define CFG1_THERM_HOT (0x10) -#define CFG1_DAC_AFC (0x20) -#define CFG1_PWM_AFC (0x40) -#define CFG1_RESET (0x80) -#define ADM1026_REG_CONFIG2 (0x01) -/* CONFIG2 controls FAN0/GPIO0 through FAN7/GPIO7 */ -#define ADM1026_REG_CONFIG3 (0x07) -#define CFG3_GPIO16_ENABLE (0x01) -#define CFG3_CI_CLEAR (0x02) -#define CFG3_VREF_250 (0x04) -#define CFG3_GPIO16_DIR (0x40) -#define CFG3_GPIO16_POL (0x80) -#define ADM1026_REG_E2CONFIG (0x13) -#define E2CFG_READ (0x01) -#define E2CFG_WRITE (0x02) -#define E2CFG_ERASE (0x04) -#define E2CFG_ROM (0x08) -#define E2CFG_CLK_EXT (0x80) - -/* There are 10 general analog inputs and 7 dedicated inputs - * They are: - * 0 - 9 = AIN0 - AIN9 - * 10 = Vbat - * 11 = 3.3V Standby - * 12 = 3.3V Main - * 13 = +5V - * 14 = Vccp (CPU core voltage) - * 15 = +12V - * 16 = -12V - */ -static u16 REG_IN[] = { - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, - 0x36, 0x37, 0x27, 0x29, 0x26, 0x2a, - 0x2b, 0x2c, 0x2d, 0x2e, 0x2f - }; -static u16 REG_IN_MIN[] = { - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, - 0x5e, 0x5f, 0x6d, 0x49, 0x6b, 0x4a, - 0x4b, 0x4c, 0x4d, 0x4e, 0x4f - }; -static u16 REG_IN_MAX[] = { - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, - 0x56, 0x57, 0x6c, 0x41, 0x6a, 0x42, - 0x43, 0x44, 0x45, 0x46, 0x47 - }; -#define ADM1026_REG_IN(nr) (REG_IN[(nr)]) -#define ADM1026_REG_IN_MIN(nr) (REG_IN_MIN[(nr)]) -#define ADM1026_REG_IN_MAX(nr) (REG_IN_MAX[(nr)]) - -/* Temperatures are: - * 0 - Internal - * 1 - External 1 - * 2 - External 2 - */ -static u16 REG_TEMP[] = { 0x1f, 0x28, 0x29 }; -static u16 REG_TEMP_MIN[] = { 0x69, 0x48, 0x49 }; -static u16 REG_TEMP_MAX[] = { 0x68, 0x40, 0x41 }; -static u16 REG_TEMP_TMIN[] = { 0x10, 0x11, 0x12 }; -static u16 REG_TEMP_THERM[] = { 0x0d, 0x0e, 0x0f }; -static u16 REG_TEMP_OFFSET[] = { 0x1e, 0x6e, 0x6f }; -#define ADM1026_REG_TEMP(nr) (REG_TEMP[(nr)]) -#define ADM1026_REG_TEMP_MIN(nr) (REG_TEMP_MIN[(nr)]) -#define ADM1026_REG_TEMP_MAX(nr) (REG_TEMP_MAX[(nr)]) -#define ADM1026_REG_TEMP_TMIN(nr) (REG_TEMP_TMIN[(nr)]) -#define ADM1026_REG_TEMP_THERM(nr) (REG_TEMP_THERM[(nr)]) -#define ADM1026_REG_TEMP_OFFSET(nr) (REG_TEMP_OFFSET[(nr)]) - -#define ADM1026_REG_FAN(nr) (0x38 + (nr)) -#define ADM1026_REG_FAN_MIN(nr) (0x60 + (nr)) -#define ADM1026_REG_FAN_DIV_0_3 (0x02) -#define ADM1026_REG_FAN_DIV_4_7 (0x03) - -#define ADM1026_REG_DAC (0x04) -#define ADM1026_REG_PWM (0x05) - -#define ADM1026_REG_GPIO_CFG_0_3 (0x08) -#define ADM1026_REG_GPIO_CFG_4_7 (0x09) -#define ADM1026_REG_GPIO_CFG_8_11 (0x0a) -#define ADM1026_REG_GPIO_CFG_12_15 (0x0b) -/* CFG_16 in REG_CFG3 */ -#define ADM1026_REG_GPIO_STATUS_0_7 (0x24) -#define ADM1026_REG_GPIO_STATUS_8_15 (0x25) -/* STATUS_16 in REG_STATUS4 */ -#define ADM1026_REG_GPIO_MASK_0_7 (0x1c) -#define ADM1026_REG_GPIO_MASK_8_15 (0x1d) -/* MASK_16 in REG_MASK4 */ - -#define ADM1026_REG_COMPANY 0x16 -#define ADM1026_REG_VERSTEP 0x17 -/* These are the recognized values for the above regs */ -#define ADM1026_COMPANY_ANALOG_DEV 0x41 -#define ADM1026_VERSTEP_GENERIC 0x40 -#define ADM1026_VERSTEP_ADM1026 0x44 - -#define ADM1026_REG_MASK1 0x18 -#define ADM1026_REG_MASK2 0x19 -#define ADM1026_REG_MASK3 0x1a -#define ADM1026_REG_MASK4 0x1b - -#define ADM1026_REG_STATUS1 0x20 -#define ADM1026_REG_STATUS2 0x21 -#define ADM1026_REG_STATUS3 0x22 -#define ADM1026_REG_STATUS4 0x23 - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - */ - -/* IN are scaled acording to built-in resistors. These are the - * voltages corresponding to 3/4 of full scale (192 or 0xc0) - * NOTE: The -12V input needs an additional factor to account - * for the Vref pullup resistor. - * NEG12_OFFSET = SCALE * Vref / V-192 - Vref - * = 13875 * 2.50 / 1.875 - 2500 - * = 16000 - */ -#if 1 -/* The values in this table are based on Table II, page 15 of the - * datasheet. - */ -static int adm1026_scaling[] = { /* .001 Volts */ - 2250, 2250, 2250, 2250, 2250, 2250, - 1875, 1875, 1875, 1875, 3000, 3330, - 3330, 4995, 2250, 12000, 13875 - }; -#define NEG12_OFFSET 16000 -#else -/* The values in this table are based on the resistors in - * Figure 5 on page 16. But the 3.3V inputs are not in - * the figure and the values for the 5V input are wrong. - * For 5V, I'm guessing that R2 at 55.2k is right, but - * the total resistance should be 1400 or 1449 like the - * other inputs. Using 1449, gives 4.922V at 192. - */ -static int adm1026_scaling[] = { /* .001 Volts */ - 2249, 2249, 2249, 2249, 2249, 2249, - 1875, 1875, 1875, 1875, 3329, 3329, - 3329, 4922, 2249, 11969, 13889 - }; -#define NEG12_OFFSET 16019 -#endif - -#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from)) -#define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,adm1026_scaling[n],192),0,255)) -#if 0 /* If we have extended A/D bits */ -#define INSEXT_FROM_REG(n,val,ext) (SCALE((val)*4 + (ext),192*4,adm1026_scaling[n])) -#define INS_FROM_REG(n,val) (INSEXT_FROM_REG(n,val,0)) -#else -#define INS_FROM_REG(n,val) (SCALE(val,192,adm1026_scaling[n])) -#endif - -/* FAN speed is measured using 22.5kHz clock and counts for 2 pulses - * and we assume a 2 pulse-per-rev fan tach signal - * 22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000 - */ -#define FAN_TO_REG(val,div) ((val)<=0 ? 0xff : SENSORS_LIMIT(1350000/((val)*(div)),1,254)) -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==0xff ? 0 : 1350000/((val)*(div))) -#define DIV_FROM_REG(val) (1<<(val)) -#define DIV_TO_REG(val) ((val)>=8 ? 3 : (val)>=4 ? 2 : (val)>=2 ? 1 : 0) - -/* Temperature is reported in 1 degC increments */ -#define TEMP_TO_REG(val) (SENSORS_LIMIT(val,-127,127)) -#define TEMP_FROM_REG(val) (val) -#define OFFSET_TO_REG(val) (SENSORS_LIMIT(val,-127,127)) -#define OFFSET_FROM_REG(val) (val) - -#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) -#define PWM_FROM_REG(val) (val) - -/* Analog output is a voltage, but it's used like a PWM - * Seems like this should be scaled, but to be consistent - * with other drivers, we do it this way. - */ -#define DAC_TO_REG(val) (SENSORS_LIMIT(val,0,255)) -#define DAC_FROM_REG(val) (val) - -/* sensors_vid.h defines vid_from_reg() */ -#define VID_FROM_REG(val,vrm) (vid_from_reg(val,vrm)) - -#define ALARMS_FROM_REG(val) (val) - -/* Unlike some other drivers we DO NOT set initial limits. Use - * the config file to set limits. - */ - -/* Typically used with systems using a v9.1 VRM spec ? */ -#define ADM1026_INIT_VRM 91 -#define ADM1026_INIT_VID -1 - -/* Chip sampling rates - * - * Some sensors are not updated more frequently than once per second - * so it doesn't make sense to read them more often than that. - * We cache the results and return the saved data if the driver - * is called again before a second has elapsed. - * - * Also, there is significant configuration data for this chip - * So, we keep the config data up to date in the cache - * when it is written and only sample it once every 5 *minutes* - */ -#define ADM1026_DATA_INTERVAL (1 * HZ) -#define ADM1026_CONFIG_INTERVAL (5 * 60 * HZ) - -/* We allow for multiple chips in a single system. - * - * For each registered ADM1026, we need to keep state information - * at client->data. The adm1026_data structure is dynamically - * allocated, when a new client structure is allocated. */ - -struct adm1026_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - int valid; /* !=0 if following fields are valid */ - unsigned long last_reading; /* In jiffies */ - unsigned long last_config; /* In jiffies */ - - u8 in[17]; /* Register value */ - u8 in_max[17]; /* Register value */ - u8 in_min[17]; /* Register value */ - s8 temp[3]; /* Register value */ - s8 temp_min[3]; /* Register value */ - s8 temp_max[3]; /* Register value */ - s8 temp_tmin[3]; /* Register value */ - s8 temp_therm[3]; /* Register value */ - s8 temp_offset[3]; /* Register value */ - u8 fan[8]; /* Register value */ - u8 fan_min[8]; /* Register value */ - u8 fan_div[8]; /* Decoded value */ - u8 pwm; /* Register value */ - u8 analog_out; /* Register value */ - int vid; /* Decoded value */ - u8 vrm; /* VRM version */ - long alarms; /* Register encoding, combined */ - long alarm_mask; /* Register encoding, combined */ - long gpio; /* Register encoding, combined */ - long gpio_mask; /* Register encoding, combined */ - u8 gpio_config[17]; /* Decoded value */ - u8 config1; /* Register value */ - u8 config2; /* Register value */ - u8 config3; /* Register value */ -}; - -static int adm1026_attach_adapter(struct i2c_adapter *adapter); -static int adm1026_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int adm1026_detach_client(struct i2c_client *client); - -static int adm1026_read_value(struct i2c_client *client, u8 register); -static int adm1026_write_value(struct i2c_client *client, u8 register, int value); -static void adm1026_print_gpio(struct i2c_client *client); -static void adm1026_fixup_gpio(struct i2c_client *client); -static void adm1026_update_client(struct i2c_client *client); -static void adm1026_init_client(struct i2c_client *client); - - -static void adm1026_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void adm1026_in16(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void adm1026_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_fixup_fan_min(struct i2c_client *client, - int fan, int old_div); -static void adm1026_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_temp_offset(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_temp_tmin(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_temp_therm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_alarm_mask(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_gpio(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_gpio_mask(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_analog_out(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1026_afc(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver adm1026_driver = { - .name = "ADM1026 compatible sensor driver", - .id = I2C_DRIVERID_ADM1026, - .flags = I2C_DF_NOTIFY, - .attach_adapter = &adm1026_attach_adapter, - .detach_client = &adm1026_detach_client, -}; - -/* Unique ID assigned to each ADM1026 detected */ -static int adm1026_id = 0; - -/* -- SENSORS SYSCTL START -- */ -#define ADM1026_SYSCTL_FAN0 1000 -#define ADM1026_SYSCTL_FAN1 1001 -#define ADM1026_SYSCTL_FAN2 1002 -#define ADM1026_SYSCTL_FAN3 1003 -#define ADM1026_SYSCTL_FAN4 1004 -#define ADM1026_SYSCTL_FAN5 1005 -#define ADM1026_SYSCTL_FAN6 1006 -#define ADM1026_SYSCTL_FAN7 1007 -#define ADM1026_SYSCTL_FAN_DIV 1008 -#define ADM1026_SYSCTL_GPIO 1009 -#define ADM1026_SYSCTL_GPIO_MASK 1010 -#define ADM1026_SYSCTL_ALARMS 1011 -#define ADM1026_SYSCTL_ALARM_MASK 1012 -#define ADM1026_SYSCTL_IN0 1013 -#define ADM1026_SYSCTL_IN1 1014 -#define ADM1026_SYSCTL_IN2 1015 -#define ADM1026_SYSCTL_IN3 1016 -#define ADM1026_SYSCTL_IN4 1017 -#define ADM1026_SYSCTL_IN5 1018 -#define ADM1026_SYSCTL_IN6 1019 -#define ADM1026_SYSCTL_IN7 1020 -#define ADM1026_SYSCTL_IN8 1021 -#define ADM1026_SYSCTL_IN9 1022 -#define ADM1026_SYSCTL_IN10 1023 -#define ADM1026_SYSCTL_IN11 1024 -#define ADM1026_SYSCTL_IN12 1025 -#define ADM1026_SYSCTL_IN13 1026 -#define ADM1026_SYSCTL_IN14 1027 -#define ADM1026_SYSCTL_IN15 1028 -#define ADM1026_SYSCTL_IN16 1029 -#define ADM1026_SYSCTL_PWM 1030 -#define ADM1026_SYSCTL_ANALOG_OUT 1031 -#define ADM1026_SYSCTL_AFC 1032 -#define ADM1026_SYSCTL_TEMP1 1033 -#define ADM1026_SYSCTL_TEMP2 1034 -#define ADM1026_SYSCTL_TEMP3 1035 -#define ADM1026_SYSCTL_TEMP_OFFSET1 1036 -#define ADM1026_SYSCTL_TEMP_OFFSET2 1037 -#define ADM1026_SYSCTL_TEMP_OFFSET3 1038 -#define ADM1026_SYSCTL_TEMP_THERM1 1039 -#define ADM1026_SYSCTL_TEMP_THERM2 1040 -#define ADM1026_SYSCTL_TEMP_THERM3 1041 -#define ADM1026_SYSCTL_TEMP_TMIN1 1042 -#define ADM1026_SYSCTL_TEMP_TMIN2 1043 -#define ADM1026_SYSCTL_TEMP_TMIN3 1044 -#define ADM1026_SYSCTL_VID 1045 -#define ADM1026_SYSCTL_VRM 1046 - -#define ADM1026_ALARM_TEMP2 (1L << 0) -#define ADM1026_ALARM_TEMP3 (1L << 1) -#define ADM1026_ALARM_IN9 (1L << 1) -#define ADM1026_ALARM_IN11 (1L << 2) -#define ADM1026_ALARM_IN12 (1L << 3) -#define ADM1026_ALARM_IN13 (1L << 4) -#define ADM1026_ALARM_IN14 (1L << 5) -#define ADM1026_ALARM_IN15 (1L << 6) -#define ADM1026_ALARM_IN16 (1L << 7) -#define ADM1026_ALARM_IN0 (1L << 8) -#define ADM1026_ALARM_IN1 (1L << 9) -#define ADM1026_ALARM_IN2 (1L << 10) -#define ADM1026_ALARM_IN3 (1L << 11) -#define ADM1026_ALARM_IN4 (1L << 12) -#define ADM1026_ALARM_IN5 (1L << 13) -#define ADM1026_ALARM_IN6 (1L << 14) -#define ADM1026_ALARM_IN7 (1L << 15) -#define ADM1026_ALARM_FAN0 (1L << 16) -#define ADM1026_ALARM_FAN1 (1L << 17) -#define ADM1026_ALARM_FAN2 (1L << 18) -#define ADM1026_ALARM_FAN3 (1L << 19) -#define ADM1026_ALARM_FAN4 (1L << 20) -#define ADM1026_ALARM_FAN5 (1L << 21) -#define ADM1026_ALARM_FAN6 (1L << 22) -#define ADM1026_ALARM_FAN7 (1L << 23) -#define ADM1026_ALARM_TEMP1 (1L << 24) -#define ADM1026_ALARM_IN10 (1L << 25) -#define ADM1026_ALARM_IN8 (1L << 26) -#define ADM1026_ALARM_THERM (1L << 27) -#define ADM1026_ALARM_AFC_FAN (1L << 28) -#define ADM1026_ALARM_UNUSED (1L << 29) -#define ADM1026_ALARM_CI (1L << 30) -/* -- SENSORS SYSCTL END -- */ - -/* The /proc/sys entries */ -/* These files are created for each detected ADM1026. This is just a template; - * The actual list is built from this and additional per-chip - * custom lists below. Note the XXX_LEN macros. These must be - * compile time constants because they will be used to allocate - * space for the final template passed to i2c_register_entry. - * We depend on the ability of GCC to evaluate expressions at - * compile time to turn these expressions into compile time - * constants, but this can generate a warning. - */ -static ctl_table adm1026_common[] = { - {ADM1026_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN9, "in9", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN10, "in10", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN11, "in11", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN12, "in12", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN13, "in13", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN14, "in14", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN15, "in15", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in}, - {ADM1026_SYSCTL_IN16, "in16", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_in16}, - - {ADM1026_SYSCTL_FAN0, "fan0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_fan}, - {ADM1026_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_fan}, - {ADM1026_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_fan}, - {ADM1026_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_fan}, - {ADM1026_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_fan}, - {ADM1026_SYSCTL_FAN5, "fan5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_fan}, - {ADM1026_SYSCTL_FAN6, "fan6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_fan}, - {ADM1026_SYSCTL_FAN7, "fan7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_fan}, - {ADM1026_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_fan_div}, - - {ADM1026_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_temp}, - {ADM1026_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_temp}, - {ADM1026_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_temp}, - {ADM1026_SYSCTL_TEMP_OFFSET1, "temp1_offset", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_offset}, - {ADM1026_SYSCTL_TEMP_OFFSET2, "temp2_offset", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_offset}, - {ADM1026_SYSCTL_TEMP_OFFSET3, "temp3_offset", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_offset}, - {ADM1026_SYSCTL_TEMP_TMIN1, "temp1_tmin", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_tmin}, - {ADM1026_SYSCTL_TEMP_TMIN2, "temp2_tmin", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_tmin}, - {ADM1026_SYSCTL_TEMP_TMIN3, "temp3_tmin", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_tmin}, - {ADM1026_SYSCTL_TEMP_THERM1, "temp1_therm", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_therm}, - {ADM1026_SYSCTL_TEMP_THERM2, "temp2_therm", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_therm}, - {ADM1026_SYSCTL_TEMP_THERM3, "temp3_therm", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_temp_therm}, - - {ADM1026_SYSCTL_VID, "vid", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_vid}, - {ADM1026_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_vrm}, - - {ADM1026_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_alarms}, - {ADM1026_SYSCTL_ALARM_MASK, "alarm_mask", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_alarm_mask}, - - {ADM1026_SYSCTL_GPIO, "gpio", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_gpio}, - {ADM1026_SYSCTL_GPIO_MASK, "gpio_mask", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_gpio_mask}, - - {ADM1026_SYSCTL_PWM, "pwm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_pwm}, - {ADM1026_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1026_analog_out}, - {ADM1026_SYSCTL_AFC, "afc", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1026_afc}, - - {0} -}; -#define CTLTBL_COMMON (sizeof(adm1026_common)/sizeof(adm1026_common[0])) - -#define MAX2(a,b) ((a)>(b)?(a):(b)) -#define MAX3(a,b,c) ((a)>(b)?MAX2((a),(c)):MAX2((b),(c))) -#define MAX4(a,b,c,d) ((a)>(b)?MAX3((a),(c),(d)):MAX3((b),(c),(d))) - -#define CTLTBL_MAX (CTLTBL_COMMON) - -/* This function is called when: - * the module is loaded - * a new adapter is loaded - */ -static int adm1026_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, adm1026_detect); -} - -/* This function is called by i2c_detect */ -static int adm1026_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - int company, verstep ; - struct i2c_client *new_client; - struct adm1026_data *data; - int err = 0; - const char *type_name = ""; - struct ctl_table template[CTLTBL_MAX] ; - struct ctl_table * template_next = template ; - - if (i2c_is_isa_adapter(adapter)) { - /* This chip has no ISA interface */ - goto ERROR0 ; - } - - if (!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BYTE_DATA)) { - /* We need to be able to do byte I/O */ - goto ERROR0 ; - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access adm1026_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct adm1026_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &adm1026_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - company = adm1026_read_value(new_client, ADM1026_REG_COMPANY); - verstep = adm1026_read_value(new_client, ADM1026_REG_VERSTEP); - -#ifdef DEBUG - printk("adm1026: Detecting device at %d,0x%02x with" - " COMPANY: 0x%02x and VERSTEP: 0x%02x\n", - i2c_adapter_id(new_client->adapter), new_client->addr, - company, verstep - ); -#endif - - /* If auto-detecting, Determine the chip type. */ - if (kind <= 0) { -#ifdef DEBUG - printk("adm1026: Autodetecting device at %d,0x%02x ...\n", - i2c_adapter_id(adapter), address ); -#endif - if( company == ADM1026_COMPANY_ANALOG_DEV - && verstep == ADM1026_VERSTEP_ADM1026 ) { - kind = adm1026 ; - } else if( company == ADM1026_COMPANY_ANALOG_DEV - && (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC ) { - printk("adm1026: Unrecgonized stepping 0x%02x" - " Defaulting to ADM1026.\n", verstep ); - kind = adm1026 ; - } else if( (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC ) { - printk("adm1026: Found version/stepping 0x%02x" - " Assuming generic ADM1026.\n", verstep ); - kind = any_chip ; - } else { -#ifdef DEBUG - printk("adm1026: Autodetection failed\n"); -#endif - /* Not an ADM1026 ... */ - if( kind == 0 ) { /* User used force=x,y */ - printk("adm1026: Generic ADM1026 Version 6 not" - " found at %d,0x%02x. Try force_adm1026.\n", - i2c_adapter_id(adapter), address ); - } - goto ERROR1; - } - } - - /* Fill in the chip specific driver values */ - switch (kind) { - case any_chip : - type_name = "adm1026"; - strcpy(new_client->name, "Generic ADM1026"); - template_next = template ; /* None used */ - break ; - case adm1026 : - type_name = "adm1026"; - strcpy(new_client->name, "Analog Devices ADM1026"); - template_next = template ; - break ; -#if 0 - /* Example of another adm1026 "compatible" device */ - case adx1000 : - type_name = "adx1000"; - strcpy(new_client->name, "Compatible ADX1000"); - memcpy( template, adx_specific, sizeof(adx_specific) ); - template_next = template + CTLTBL_ADX1000 ; - break ; -#endif - default : - printk("adm1026: Internal error, invalid kind (%d)!", kind); - err = -EFAULT ; - goto ERROR1; - } - - /* Fill in the remaining client fields */ - new_client->id = adm1026_id++; - printk("adm1026(%d): Assigning ID %d to %s at %d,0x%02x\n", - new_client->id, new_client->id, new_client->name, - i2c_adapter_id(new_client->adapter), - new_client->addr - ); - - /* Housekeeping values */ - data->type = kind; - data->valid = 0; - - /* Set the VRM version */ - data->vrm = ADM1026_INIT_VRM ; - data->vid = ADM1026_INIT_VID ; - - init_MUTEX(&data->update_lock); - - /* Initialize the ADM1026 chip */ - adm1026_init_client(new_client); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR1; - - /* Finish out the template */ - memcpy(template_next, adm1026_common, sizeof(adm1026_common)); - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR2; - } - data->sysctl_id = i; - - return 0; - - /* Error out and cleanup code */ - ERROR2: - i2c_detach_client(new_client); - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int adm1026_detach_client(struct i2c_client *client) -{ - int err; - int id ; - - id = client->id; - i2c_deregister_entry(((struct adm1026_data *)(client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("adm1026(%d): Client deregistration failed," - " client not detached.\n", id ); - return err; - } - - kfree(client->data); - - return 0; -} - -static int adm1026_read_value(struct i2c_client *client, u8 reg) -{ - int res; - - if( reg < 0x80 ) { - /* "RAM" locations */ - res = i2c_smbus_read_byte_data(client, reg) & 0xff ; - } else { - /* EEPROM, do nothing */ - res = 0 ; - } - - return res ; -} - -static int adm1026_write_value(struct i2c_client *client, u8 reg, int value) -{ - int res ; - - if( reg < 0x80 ) { - /* "RAM" locations */ - res = i2c_smbus_write_byte_data(client, reg, value); - } else { - /* EEPROM, do nothing */ - res = 0 ; - } - - return res ; -} - -/* Called when we have found a new ADM1026. */ -static void adm1026_init_client(struct i2c_client *client) -{ - int value ; - int i; - struct adm1026_data *data = client->data; - -#ifdef DEBUG - printk("adm1026(%d): Initializing device\n", client->id); -#endif - - /* Read chip config */ - data->config1 = adm1026_read_value(client, ADM1026_REG_CONFIG1); - data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2); - data->config3 = adm1026_read_value(client, ADM1026_REG_CONFIG3); - - /* Inform user of chip config */ -#ifdef DEBUG - printk("adm1026(%d): ADM1026_REG_CONFIG1 is: 0x%02x\n", - client->id, data->config1 ); -#endif - if( (data->config1 & CFG1_MONITOR) == 0 ) { - printk("adm1026(%d): Monitoring not currently enabled.\n", - client->id ); - } - if( data->config1 & CFG1_INT_ENABLE ) { - printk("adm1026(%d): SMBALERT interrupts are enabled.\n", - client->id ); - } - if( data->config1 & CFG1_AIN8_9 ) { - printk("adm1026(%d): in8 and in9 enabled. temp3 disabled.\n", - client->id ); - } else { - printk("adm1026(%d): temp3 enabled. in8 and in9 disabled.\n", - client->id ); - } - if( data->config1 & CFG1_THERM_HOT ) { - printk("adm1026(%d): Automatic THERM, PWM, and temp limits enabled.\n", - client->id ); - } - - value = data->config3 ; - if( data->config3 & CFG3_GPIO16_ENABLE ) { - printk("adm1026(%d): GPIO16 enabled. THERM pin disabled.\n", - client->id ); - } else { - printk("adm1026(%d): THERM pin enabled. GPIO16 disabled.\n", - client->id ); - } - if( data->config3 & CFG3_VREF_250 ) { - printk("adm1026(%d): Vref is 2.50 Volts.\n", client->id ); - } else { - printk("adm1026(%d): Vref is 1.82 Volts.\n", client->id ); - } - - /* Read and pick apart the existing GPIO configuration */ - value = 0 ; - for( i = 0 ; i <= 15 ; ++i ) { - if( (i & 0x03) == 0 ) { - value = adm1026_read_value(client, - ADM1026_REG_GPIO_CFG_0_3 + i/4 ); - } - data->gpio_config[i] = value & 0x03 ; - value >>= 2 ; - } - data->gpio_config[16] = (data->config3 >> 6) & 0x03 ; - - /* ... and then print it */ - adm1026_print_gpio(client); - - /* If the user asks us to reprogram the GPIO config, then - * do it now. But only if this is the first ADM1026. - */ - if( client->id == 0 - && (gpio_input[0] != -1 || gpio_output[0] != -1 - || gpio_inverted[0] != -1 || gpio_normal[0] != -1 - || gpio_fan[0] != -1 ) ) { - adm1026_fixup_gpio(client); - } - - /* WE INTENTIONALLY make no changes to the limits, - * offsets, pwms and fans. If they were - * configured, we don't want to mess with them. - * If they weren't, the default is generally safe - * and will suffice until 'sensors -s' can be run. - */ - - /* Start monitoring */ - value = adm1026_read_value(client, ADM1026_REG_CONFIG1); - - /* Set MONITOR, clear interrupt acknowledge and s/w reset */ - value = (value | CFG1_MONITOR) & (~CFG1_INT_CLEAR & ~CFG1_RESET) ; -#ifdef DEBUG - printk("adm1026(%d): Setting CONFIG to: 0x%02x\n", client->id, value ); -#endif - data->config1 = value ; - adm1026_write_value(client, ADM1026_REG_CONFIG1, value); - -} - -static void adm1026_print_gpio(struct i2c_client *client) -{ - struct adm1026_data *data = client->data; - int i ; - - printk("adm1026(%d): GPIO config is:\nadm1026(%d):", - client->id, client->id ); - for( i = 0 ; i <= 7 ; ++i ) { - if( data->config2 & (1 << i) ) { - printk( " %sGP%s%d", - data->gpio_config[i] & 0x02 ? "" : "!", - data->gpio_config[i] & 0x01 ? "OUT" : "IN", - i ); - } else { - printk( " FAN%d", i ); - } - } - printk( "\nadm1026(%d):", client->id ); - for( i = 8 ; i <= 15 ; ++i ) { - printk( " %sGP%s%d", - data->gpio_config[i] & 0x02 ? "" : "!", - data->gpio_config[i] & 0x01 ? "OUT" : "IN", - i ); - } - if( data->config3 & CFG3_GPIO16_ENABLE ) { - printk( " %sGP%s16\n", - data->gpio_config[16] & 0x02 ? "" : "!", - data->gpio_config[16] & 0x01 ? "OUT" : "IN" ); - } else { - /* GPIO16 is THERM */ - printk( " THERM\n" ); - } -} - -static void adm1026_fixup_gpio(struct i2c_client *client) -{ - struct adm1026_data *data = client->data; - int i ; - int value ; - - /* Make the changes requested. */ - /* We may need to unlock/stop monitoring or soft-reset the - * chip before we can make changes. This hasn't been - * tested much. FIXME - */ - - /* Make outputs */ - for( i = 0 ; i <= 16 ; ++i ) { - if( gpio_output[i] >= 0 && gpio_output[i] <= 16 ) { - data->gpio_config[gpio_output[i]] |= 0x01 ; - } - /* if GPIO0-7 is output, it isn't a FAN tach */ - if( gpio_output[i] >= 0 && gpio_output[i] <= 7 ) { - data->config2 |= 1 << gpio_output[i] ; - } - } - - /* Input overrides output */ - for( i = 0 ; i <= 16 ; ++i ) { - if( gpio_input[i] >= 0 && gpio_input[i] <= 16 ) { - data->gpio_config[gpio_input[i]] &= ~ 0x01 ; - } - /* if GPIO0-7 is input, it isn't a FAN tach */ - if( gpio_input[i] >= 0 && gpio_input[i] <= 7 ) { - data->config2 |= 1 << gpio_input[i] ; - } - } - - /* Inverted */ - for( i = 0 ; i <= 16 ; ++i ) { - if( gpio_inverted[i] >= 0 && gpio_inverted[i] <= 16 ) { - data->gpio_config[gpio_inverted[i]] &= ~ 0x02 ; - } - } - - /* Normal overrides inverted */ - for( i = 0 ; i <= 16 ; ++i ) { - if( gpio_normal[i] >= 0 && gpio_normal[i] <= 16 ) { - data->gpio_config[gpio_normal[i]] |= 0x02 ; - } - } - - /* Fan overrides input and output */ - for( i = 0 ; i <= 7 ; ++i ) { - if( gpio_fan[i] >= 0 && gpio_fan[i] <= 7 ) { - data->config2 &= ~( 1 << gpio_fan[i] ); - } - } - - /* Write new configs to registers */ - adm1026_write_value(client, ADM1026_REG_CONFIG2, data->config2); - data->config3 = (data->config3 & 0x3f) - | ((data->gpio_config[16] & 0x03) << 6) ; - adm1026_write_value(client, ADM1026_REG_CONFIG3, data->config3); - for( i = 15, value = 0 ; i >= 0 ; --i ) { - value <<= 2 ; - value |= data->gpio_config[i] & 0x03 ; - if( (i & 0x03) == 0 ) { - adm1026_write_value(client, - ADM1026_REG_GPIO_CFG_0_3 + i/4, - value ); - value = 0 ; - } - } - - /* Print the new config */ - adm1026_print_gpio(client); -} - -static void adm1026_update_client(struct i2c_client *client) -{ - struct adm1026_data *data = client->data; - int i; - long value, alarms, gpio ; - - down(&data->update_lock); - - if (!data->valid - || (jiffies - data->last_reading > ADM1026_DATA_INTERVAL )) { - /* Things that change quickly */ - -#ifdef DEBUG - printk("adm1026(%d): Reading sensor values\n", client->id); -#endif - for (i = 0 ; i <= 16 ; ++i) { - data->in[i] = - adm1026_read_value(client, ADM1026_REG_IN(i)); - } - - for (i = 0 ; i <= 7 ; ++i) { - data->fan[i] = - adm1026_read_value(client, ADM1026_REG_FAN(i)); - } - - for (i = 0 ; i <= 2 ; ++i) { - /* NOTE: temp[] is s8 and we assume 2's complement - * "conversion" in the assignment */ - data->temp[i] = - adm1026_read_value(client, ADM1026_REG_TEMP(i)); - } - - data->pwm = adm1026_read_value(client, ADM1026_REG_PWM); - data->analog_out = adm1026_read_value(client, ADM1026_REG_DAC); - - /* GPIO16 is MSbit of alarms, move it to gpio */ - alarms = adm1026_read_value(client, ADM1026_REG_STATUS4); - gpio = alarms & 0x80 ? 0x0100 : 0 ; /* GPIO16 */ - alarms &= 0x7f ; - alarms <<= 8 ; - alarms |= adm1026_read_value(client, ADM1026_REG_STATUS3); - alarms <<= 8 ; - alarms |= adm1026_read_value(client, ADM1026_REG_STATUS2); - alarms <<= 8 ; - alarms |= adm1026_read_value(client, ADM1026_REG_STATUS1); - data->alarms = alarms ; - - /* Read the GPIO values */ - gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_STATUS_8_15); - gpio <<= 8 ; - gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_STATUS_0_7); - data->gpio = gpio ; - - data->last_reading = jiffies ; - }; /* last_reading */ - - if (!data->valid - || (jiffies - data->last_config > ADM1026_CONFIG_INTERVAL) ) { - /* Things that don't change often */ - -#ifdef DEBUG - printk("adm1026(%d): Reading config values\n", client->id); -#endif - for (i = 0 ; i <= 16 ; ++i) { - data->in_min[i] = - adm1026_read_value(client, ADM1026_REG_IN_MIN(i)); - data->in_max[i] = - adm1026_read_value(client, ADM1026_REG_IN_MAX(i)); - } - - value = adm1026_read_value(client, ADM1026_REG_FAN_DIV_0_3) - | (adm1026_read_value(client, ADM1026_REG_FAN_DIV_4_7) << 8); - for (i = 0 ; i <= 7 ; ++i) { - data->fan_min[i] = - adm1026_read_value(client, ADM1026_REG_FAN_MIN(i)); - data->fan_div[i] = DIV_FROM_REG(value & 0x03); - value >>= 2 ; - } - - for (i = 0; i <= 2; ++i) { - /* NOTE: temp_xxx[] are s8 and we assume 2's complement - * "conversion" in the assignment */ - data->temp_min[i] = - adm1026_read_value(client, ADM1026_REG_TEMP_MIN(i)); - data->temp_max[i] = - adm1026_read_value(client, ADM1026_REG_TEMP_MAX(i)); - data->temp_tmin[i] = - adm1026_read_value(client, ADM1026_REG_TEMP_TMIN(i)); - data->temp_therm[i] = - adm1026_read_value(client, ADM1026_REG_TEMP_THERM(i)); - data->temp_offset[i] = - adm1026_read_value(client, ADM1026_REG_TEMP_OFFSET(i)); - } - - /* Read the STATUS/alarm masks */ - alarms = adm1026_read_value(client, ADM1026_REG_MASK4); - gpio = alarms & 0x80 ? 0x0100 : 0 ; /* GPIO16 */ - alarms = (alarms & 0x7f) << 8 ; - alarms |= adm1026_read_value(client, ADM1026_REG_MASK3); - alarms <<= 8 ; - alarms |= adm1026_read_value(client, ADM1026_REG_MASK2); - alarms <<= 8 ; - alarms |= adm1026_read_value(client, ADM1026_REG_MASK1); - data->alarm_mask = alarms ; - - /* Read the GPIO values */ - gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_MASK_8_15); - gpio <<= 8 ; - gpio |= adm1026_read_value(client, ADM1026_REG_GPIO_MASK_0_7); - data->gpio_mask = gpio ; - - /* Read the GPIO config */ - data->config2 = adm1026_read_value(client, ADM1026_REG_CONFIG2); - data->config3 = adm1026_read_value(client, ADM1026_REG_CONFIG3); - data->gpio_config[16] = (data->config3 >> 6) & 0x03 ; - - value = 0 ; - for( i = 0 ; i <= 15 ; ++i ) { - if( (i & 0x03) == 0 ) { - value = adm1026_read_value(client, - ADM1026_REG_GPIO_CFG_0_3 + i/4 ); - } - data->gpio_config[i] = value & 0x03 ; - value >>= 2 ; - } - - data->last_config = jiffies; - }; /* last_config */ - - /* We don't know where or even _if_ the VID might be on the GPIO - * pins. But the datasheet gives an example config showing - * GPIO11-15 being used to monitor VID0-4, so we go with that - * but make the vid WRITEABLE so if it's wrong, the user can - * set it in /etc/sensors.conf perhaps using an expression or - * 0 to trigger a re-read from the GPIO pins. - */ - if( data->vid == ADM1026_INIT_VID ) { - /* Hasn't been set yet, make a bold assumption */ - printk("adm1026(%d): Setting VID from GPIO11-15.\n", - client->id ); - data->vid = (data->gpio >> 11) & 0x1f ; - } - - data->valid = 1; - - up(&data->update_lock); -} - - -/* The following functions are the call-back functions of the /proc/sys and - sysctl files. The appropriate function is referenced in the ctl_table - extra1 field. - - Each function must return the magnitude (power of 10 to divide the - data with) if it is called with operation set to SENSORS_PROC_REAL_INFO. - It must put a maximum of *nrels elements in results reflecting the - data of this file, and set *nrels to the number it actually put in - it, if operation is SENSORS_PROC_REAL_READ. Finally, it must get - up to *nrels elements from results and write them to the chip, if - operations is SENSORS_PROC_REAL_WRITE. - */ -void adm1026_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - int nr = ctl_name - ADM1026_SYSCTL_IN0; - - /* We handle in0 - in15 here. in16 (-12V) is handled below */ - if (nr < 0 || nr > 15) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; /* 1.000 */ - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = INS_FROM_REG(nr,data->in_min[nr]); - results[1] = INS_FROM_REG(nr,data->in_max[nr]); - results[2] = INS_FROM_REG(nr,data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 1) { - data->in_max[nr] = INS_TO_REG(nr,results[1]); - adm1026_write_value(client, ADM1026_REG_IN_MAX(nr), - data->in_max[nr]); - } - if (*nrels_mag > 0) { - data->in_min[nr] = INS_TO_REG(nr,results[0]); - adm1026_write_value(client, ADM1026_REG_IN_MIN(nr), - data->in_min[nr]); - } - up(&data->update_lock); - } -} - -void adm1026_in16(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - int nr = ctl_name - ADM1026_SYSCTL_IN0; - - /* We handle in16 (-12V) here */ - if (nr != 16) - return ; /* ERROR */ - - /* Apply offset and swap min/max so that min is 90% of - * target and max is 110% of target. - */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; /* 1.000 */ - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = INS_FROM_REG(nr,data->in_max[nr])-NEG12_OFFSET ; - results[1] = INS_FROM_REG(nr,data->in_min[nr])-NEG12_OFFSET ; - results[2] = INS_FROM_REG(nr,data->in[nr])-NEG12_OFFSET ; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 1) { - data->in_min[nr] = INS_TO_REG(nr,results[1]+NEG12_OFFSET); - adm1026_write_value(client, ADM1026_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag > 0) { - data->in_max[nr] = INS_TO_REG(nr,results[0]+NEG12_OFFSET); - adm1026_write_value(client, ADM1026_REG_IN_MAX(nr), - data->in_max[nr]); - } - up(&data->update_lock); - } -} - -void adm1026_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - int nr = ctl_name - ADM1026_SYSCTL_FAN0 ; - - if (nr < 0 || nr > 7) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr], data->fan_div[nr]); - results[1] = FAN_FROM_REG(data->fan[nr], data->fan_div[nr]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->fan_min[nr] = FAN_TO_REG(results[0], - data->fan_div[nr]); - adm1026_write_value(client, ADM1026_REG_FAN_MIN(nr), - data->fan_min[nr]); - } - up(&data->update_lock); - } -} - -/* Adjust fan_min to account for new fan divisor */ -void adm1026_fixup_fan_min(struct i2c_client *client, int fan, int old_div) -{ - struct adm1026_data *data = client->data; - int new_div = data->fan_div[fan] ; - int new_min; - - /* 0 and 0xff are special. Don't adjust them */ - if( data->fan_min[fan] == 0 || data->fan_min[fan] == 0xff ) { - return ; - } - - new_min = data->fan_min[fan] * old_div / new_div ; - new_min = SENSORS_LIMIT(new_min, 1, 254); - data->fan_min[fan] = new_min ; - adm1026_write_value(client, ADM1026_REG_FAN_MIN(fan), new_min); -} - -void adm1026_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - int i ; - int value, div, old ; - - if (ctl_name != ADM1026_SYSCTL_FAN_DIV) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - for( i = 0 ; i <= 7 ; ++i ) { - results[i] = data->fan_div[i] ; - } - *nrels_mag = 8; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - value = 0 ; - for( i = 7 ; i >= 0 ; --i ) { - value <<= 2 ; - if (*nrels_mag > i) { - old = data->fan_div[i] ; - div = DIV_TO_REG(results[i]) ; - data->fan_div[i] = DIV_FROM_REG(div) ; - if( data->fan_div[i] != old ) { - adm1026_fixup_fan_min(client,i,old); - } - } else { - div = DIV_TO_REG(data->fan_div[i]) ; - } - value |= div ; - } - adm1026_write_value(client, ADM1026_REG_FAN_DIV_0_3, - value & 0xff); - adm1026_write_value(client, ADM1026_REG_FAN_DIV_4_7, - (value >> 8) & 0xff); - up(&data->update_lock); - } -} - -void adm1026_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - int nr = ctl_name - ADM1026_SYSCTL_TEMP1 ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_min[nr]); - results[1] = TEMP_FROM_REG(data->temp_max[nr]); - results[2] = TEMP_FROM_REG(data->temp[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 1) { - data->temp_max[nr] = TEMP_TO_REG(results[1]); - adm1026_write_value(client, ADM1026_REG_TEMP_MAX(nr), - data->temp_max[nr]); - } - if (*nrels_mag > 0) { - data->temp_min[nr] = TEMP_TO_REG(results[0]); - adm1026_write_value(client, ADM1026_REG_TEMP_MIN(nr), - data->temp_min[nr]); - } - up(&data->update_lock); - } -} - -void adm1026_temp_offset(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - int nr = ctl_name - ADM1026_SYSCTL_TEMP_OFFSET1 ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_offset[nr]); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->temp_offset[nr] = TEMP_TO_REG(results[0]); - adm1026_write_value(client, ADM1026_REG_TEMP_OFFSET(nr), - data->temp_offset[nr]); - } - up(&data->update_lock); - } -} - -void adm1026_temp_tmin(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - int nr = ctl_name - ADM1026_SYSCTL_TEMP_TMIN1 ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_tmin[nr]); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->temp_tmin[nr] = TEMP_TO_REG(results[0]); - adm1026_write_value(client, ADM1026_REG_TEMP_TMIN(nr), - data->temp_tmin[nr]); - } - up(&data->update_lock); - } -} - -void adm1026_temp_therm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - int nr = ctl_name - ADM1026_SYSCTL_TEMP_THERM1 ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_therm[nr]); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->temp_therm[nr] = TEMP_TO_REG(results[0]); - adm1026_write_value(client, ADM1026_REG_TEMP_THERM(nr), - data->temp_therm[nr]); - } - up(&data->update_lock); - } -} - -void adm1026_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - - if (ctl_name != ADM1026_SYSCTL_PWM) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = PWM_FROM_REG(data->pwm); - results[1] = 1 ; /* Always enabled */ - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - /* PWM enable is read-only */ - if (*nrels_mag > 0) { - data->pwm = PWM_TO_REG(results[0]); - adm1026_write_value(client, ADM1026_REG_PWM, - data->pwm); - } - up(&data->update_lock); - } -} - -void adm1026_analog_out(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - - if (ctl_name != ADM1026_SYSCTL_ANALOG_OUT) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* 0 - 255 */ - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = DAC_FROM_REG(data->analog_out); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->analog_out = DAC_TO_REG(results[0]); - adm1026_write_value(client, ADM1026_REG_DAC, - data->analog_out); - } - up(&data->update_lock); - } -} - -void adm1026_afc(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - - if (ctl_name != ADM1026_SYSCTL_AFC) - return ; /* ERROR */ - - /* PWM auto fan control, DAC auto fan control */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = (data->config1 & CFG1_PWM_AFC) != 0 ; - results[1] = (data->config1 & CFG1_DAC_AFC) != 0 ; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 1) { - data->config1 = (data->config1 & ~CFG1_DAC_AFC) - | (results[1] ? CFG1_DAC_AFC : 0) ; - } - if (*nrels_mag > 0) { - data->config1 = (data->config1 & ~CFG1_PWM_AFC) - | (results[0] ? CFG1_PWM_AFC : 0) ; - adm1026_write_value(client, ADM1026_REG_CONFIG1, - data->config1); - } - up(&data->update_lock); - } -} - -void adm1026_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - - if( ctl_name != ADM1026_SYSCTL_VID ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = VID_FROM_REG((data->vid)&0x3f,data->vrm); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - /* Hmmm... There isn't a VID_TO_REG mapping */ - if (*nrels_mag > 0) { - if( results[0] >= 0 ) { - data->vid = results[0] & 0x3f ; - } else { - data->vid = ADM1026_INIT_VID ; - } - } - up(&data->update_lock); - } - -} - -void adm1026_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - - if( ctl_name != ADM1026_SYSCTL_VRM ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm ; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag > 0) { - data->vrm = results[0] ; - } - } -} - -void adm1026_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - - if( ctl_name != ADM1026_SYSCTL_ALARMS ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = data->alarms ; - *nrels_mag = 1; - } - /* FIXME: Perhaps we should implement a write function - * to clear an alarm? - */ -} - -void adm1026_alarm_mask(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - unsigned long mask ; - - if( ctl_name != ADM1026_SYSCTL_ALARM_MASK ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = data->alarm_mask ; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->alarm_mask = results[0] & 0x7fffffff ; - mask = data->alarm_mask - | (data->gpio_mask & 0x10000 ? 0x80000000 : 0) ; - adm1026_write_value(client, ADM1026_REG_MASK1, - mask & 0xff); - mask >>= 8 ; - adm1026_write_value(client, ADM1026_REG_MASK2, - mask & 0xff); - mask >>= 8 ; - adm1026_write_value(client, ADM1026_REG_MASK3, - mask & 0xff); - mask >>= 8 ; - adm1026_write_value(client, ADM1026_REG_MASK4, - mask & 0xff); - } - up(&data->update_lock); - } -} - -void adm1026_gpio(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - long gpio ; - - if( ctl_name != ADM1026_SYSCTL_GPIO ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = data->gpio ; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->gpio = results[0] & 0x1ffff ; - gpio = data->gpio ; - adm1026_write_value(client, - ADM1026_REG_GPIO_STATUS_0_7, - gpio & 0xff ); - gpio >>= 8 ; - adm1026_write_value(client, - ADM1026_REG_GPIO_STATUS_8_15, - gpio & 0xff ); - gpio = ((gpio >> 1) & 0x80) - | (data->alarms >> 24 & 0x7f); - adm1026_write_value(client, - ADM1026_REG_STATUS4, - gpio & 0xff ); - } - up(&data->update_lock); - } -} - -void adm1026_gpio_mask(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm1026_data *data = client->data; - long mask ; - - if( ctl_name != ADM1026_SYSCTL_GPIO_MASK ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1026_update_client(client); - results[0] = data->gpio_mask ; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->gpio_mask = results[0] & 0x1ffff ; - mask = data->gpio_mask ; - adm1026_write_value(client, ADM1026_REG_GPIO_MASK_0_7, - mask & 0xff); - mask >>= 8 ; - adm1026_write_value(client, ADM1026_REG_GPIO_MASK_8_15, - mask & 0xff); - mask = ((mask >> 1) & 0x80) - | (data->alarm_mask >> 24 & 0x7f); - adm1026_write_value(client, ADM1026_REG_MASK1, - mask & 0xff); - } - up(&data->update_lock); - } -} - -static int __init sm_adm1026_init(void) -{ - printk("adm1026: Version %s (%s)\n", LM_VERSION, LM_DATE); - printk("adm1026: See http://www.penguincomputing.com/lm_sensors for more info.\n" ); - return i2c_add_driver(&adm1026_driver); -} - -static void __exit sm_adm1026_exit(void) -{ - i2c_del_driver(&adm1026_driver); -} - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Philip Pokorny and - Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -/* Following macros take channel parameter starting from 0 */ -#define ADM1031_REG_FAN_SPEED(nr) (0x08 + (nr)) - -#define ADM1031_REG_FAN_DIV(nr) (0x20 + (nr)) -#define ADM1031_REG_FAN_MIN(nr) (0x10 + (nr)) - -#define ADM1031_REG_TEMP_MAX(nr) (0x14 + 4 * (nr)) -#define ADM1031_REG_TEMP_MIN(nr) (0x15 + 4 * (nr)) -#define ADM1031_REG_TEMP_CRIT(nr) (0x16 + 4 * (nr)) - -#define ADM1031_REG_TEMP(nr) (0x0a + (nr)) -#define ADM1031_REG_AUTO_TEMP(nr) (0x24 + (nr)) - -#define ADM1031_REG_STATUS(nr) (0x02 + (nr)) -#define ADM1031_REG_FAN_PWM 0x22 - -#define ADM1031_REG_CONF1 0x00 -#define ADM1031_REG_CONF2 0x01 -#define ADM1031_REG_EXT_TEMP 0x06 - -#define ADM1031_CONF1_MONITOR_ENABLE 0x01 /* Monitoring enable */ -#define ADM1031_CONF1_PWM_INVERT 0x08 /* PWM Invert (unused) */ -#define ADM1031_CONF1_AUTO_MODE 0x80 /* Auto fan mode */ - -#define ADM1031_CONF2_PWM1_ENABLE 0x01 -#define ADM1031_CONF2_PWM2_ENABLE 0x02 -#define ADM1031_CONF2_TACH1_ENABLE 0x04 -#define ADM1031_CONF2_TACH2_ENABLE 0x08 -#define ADM1031_CONF2_TEMP_ENABLE(chan) (0x10 << (chan)) - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_2(adm1030, adm1031); - -/* - * Proc entries - * These files are created for each detected ADM1031. - */ - -/* -- SENSORS SYSCTL START -- */ - -#define ADM1031_SYSCTL_TEMP1 1200 -#define ADM1031_SYSCTL_TEMP2 1201 -#define ADM1031_SYSCTL_TEMP3 1202 - -#define ADM1031_SYSCTL_FAN1 1210 -#define ADM1031_SYSCTL_FAN2 1211 - -#define ADM1031_SYSCTL_FAN_DIV 1220 - -#define ADM1031_SYSCTL_ALARMS 1250 - -#define ADM1031_ALARM_FAN1_MIN 0x0001 -#define ADM1031_ALARM_FAN1_FLT 0x0002 -#define ADM1031_ALARM_TEMP2_HIGH 0x0004 -#define ADM1031_ALARM_TEMP2_LOW 0x0008 -#define ADM1031_ALARM_TEMP2_CRIT 0x0010 -#define ADM1031_ALARM_TEMP2_DIODE 0x0020 -#define ADM1031_ALARM_TEMP1_HIGH 0x0040 -#define ADM1031_ALARM_TEMP1_LOW 0x0080 -#define ADM1031_ALARM_FAN2_MIN 0x0100 -#define ADM1031_ALARM_FAN2_FLT 0x0200 -#define ADM1031_ALARM_TEMP3_HIGH 0x0400 -#define ADM1031_ALARM_TEMP3_LOW 0x0800 -#define ADM1031_ALARM_TEMP3_CRIT 0x1000 -#define ADM1031_ALARM_TEMP3_DIODE 0x2000 -#define ADM1031_ALARM_TEMP1_CRIT 0x4000 -#define ADM1031_ALARM_THERMAL 0x8000 - - -/* -- SENSORS SYSCTL END -- */ -static void adm1031_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1031_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1031_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1031_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static ctl_table adm1031_dir_table_template[] = { - {ADM1031_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_temp}, - {ADM1031_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_temp}, - {ADM1031_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_temp}, - {ADM1031_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_fan}, - {ADM1031_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_fan_div}, - {ADM1031_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_fan}, - {ADM1031_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_alarms}, - {0} -}; - -static ctl_table adm1030_dir_table_template[] = { - {ADM1031_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_temp}, - {ADM1031_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_temp}, - {ADM1031_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_fan}, - {ADM1031_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_fan_div}, - {ADM1031_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1031_alarms}, - {0} -}; - - -/* Each client has this additional data */ -struct adm1031_data { - struct i2c_client client; - int sysctl_id; - struct semaphore update_lock; - int chip_type; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u16 alarms; - u8 conf1; - u8 conf2; - u8 fan[2]; - u8 fan_min[2]; - u8 fan_pwm[2]; - u8 fan_div[2]; - s8 temp[3]; - u8 auto_temp[3]; - u8 ext_temp[3]; - s8 temp_min[3]; - s8 temp_max[3]; - s8 temp_crit[3]; -}; - -static int adm1031_attach_adapter(struct i2c_adapter *adapter); -static int adm1031_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void adm1031_init_client(struct i2c_client *client); -static int adm1031_detach_client(struct i2c_client *client); - -static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg); -static inline int adm1031_write_value(struct i2c_client *client, u8 reg, - unsigned int value); - -static void adm1031_update_client(struct i2c_client *client); - -/* This is the driver that will be inserted */ -static struct i2c_driver adm1031_driver = { - .name = "ADM1031/ADM1030 sensor driver", - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm1031_attach_adapter, - .detach_client = adm1031_detach_client, -}; - -#define TEMP_TO_REG(val) ((val) < 0 ? (((val) - 500) / 1000) : \ - (((val) + 500) / 1000)) - -#define TEMP_FROM_REG(reg) ((reg) * 1000) - -#define TEMP_FROM_REG_EXT(val,ext) (TEMP_FROM_REG(val) + (ext) * 125) - -#define FAN_FROM_REG(reg,div) ((reg) ? 675000 / ((reg) * (div)) : 0) - -#define FAN_TO_REG(val,div) ((val) <= 0 ? 0 : \ - (val) * (div) >= 675000 ? 1 : \ - (val) * (div) <= 2647 ? 255 : \ - 675000 / ((val) * (div))) - -#define FAN_DIV_TO_REG(val) ((val) == 8 ? 0xc0 : \ - (val) == 4 ? 0x80 : \ - (val) == 1 ? 0x00 : 0x40) - -#define FAN_DIV_FROM_REG(reg) (1 << (((reg)&0xc0) >> 6)) - -#define AUTO_TEMP_MIN_FROM_REG(reg) (((reg) >> 3) * 4) - - -static int adm1031_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, adm1031_detect); -} - -/* This function is called by i2c_detect */ -static int -adm1031_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - struct i2c_client *new_client; - struct adm1031_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto exit; - - if (!(data = kmalloc(sizeof(struct adm1031_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - memset(data, 0, sizeof(struct adm1031_data)); - - new_client = &data->client; - new_client->data = data; - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm1031_driver; - new_client->flags = 0; - - if (kind < 0) { - int id, co; - id = i2c_smbus_read_byte_data(new_client, 0x3d); - co = i2c_smbus_read_byte_data(new_client, 0x3e); - - if (((id != 0x31) || (id != 0x30)) && (co != 0x41)) - goto exit_free; - kind = (id == 0x30) ? adm1030 : adm1031; - } - - if (kind <= 0) - kind = adm1031; - - /* Given the detected chip type, set the chip name and the - * auto fan control helper table. */ - if (kind == adm1030) { - type_name = "adm1030"; - client_name = "ADM1030 chip"; - - } else if (kind == adm1031) { - type_name = "adm1031"; - client_name = "ADM1031 chip"; - } - data->chip_type = kind; - - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - - if (kind == adm1030) { - if ((err = i2c_register_entry(new_client, type_name, - adm1030_dir_table_template, - THIS_MODULE)) < 0) - goto exit_detach; - } else if (kind == adm1031) { - if ((err = i2c_register_entry(new_client, type_name, - adm1031_dir_table_template, - THIS_MODULE)) < 0) - goto exit_detach; - } - - data->sysctl_id = err; - - /* Initialize the ADM1031 chip */ - adm1031_init_client(new_client); - - return 0; - -exit_detach: - i2c_detach_client(new_client); -exit_free: - kfree(data); -exit: - return err; -} - -static int adm1031_detach_client(struct i2c_client *client) -{ - int ret; - struct adm1031_data *data = client->data; - - i2c_deregister_entry(data->sysctl_id); - if ((ret = i2c_detach_client(client)) != 0) { - return ret; - } - - kfree(data); - return 0; -} - -static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static inline int adm1031_write_value(struct i2c_client *client, u8 reg, - unsigned int value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static void adm1031_init_client(struct i2c_client *client) -{ - unsigned int read_val; - unsigned int mask; - struct adm1031_data *data = client->data; - - mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE); - if (data->chip_type == adm1031) { - mask |= (ADM1031_CONF2_PWM2_ENABLE | - ADM1031_CONF2_TACH2_ENABLE); - } - /* Initialize the ADM1031 chip (enable fan speed reading) */ - read_val = adm1031_read_value(client, ADM1031_REG_CONF2); - if ((read_val | mask) != read_val) { - adm1031_write_value(client, ADM1031_REG_CONF2, - read_val | mask); - } - - read_val = adm1031_read_value(client, ADM1031_REG_CONF1); - if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) { - adm1031_write_value(client, ADM1031_REG_CONF1, read_val | - ADM1031_CONF1_MONITOR_ENABLE); - } -} - -static void adm1031_update_client(struct i2c_client *client) -{ - struct adm1031_data *data = client->data; - int chan; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { -#ifdef DEBUG - printk(KERN_INFO "adm1031.o: Starting chip update\n"); -#endif - for (chan = 0; - chan < ((data->chip_type == adm1031) ? 3 : 2); - chan++) { - u8 oldh, newh; - - oldh = adm1031_read_value(client, - ADM1031_REG_TEMP(chan)); - data->ext_temp[chan] = adm1031_read_value(client, - ADM1031_REG_EXT_TEMP); - newh = adm1031_read_value(client, - ADM1031_REG_TEMP(chan)); - if (newh != oldh) { - data->ext_temp[chan] = adm1031_read_value(client, - ADM1031_REG_EXT_TEMP); -#ifdef DEBUG - oldh = adm1031_read_value(client, - ADM1031_REG_TEMP(chan)); - - /* oldh is actually newer */ - if (newh != oldh) - printk(KERN_INFO "adm1031.o: Remote " - "temperature may be wrong.\n"); -#endif - } - data->temp[chan] = newh; - - data->temp_min[chan] = adm1031_read_value(client, - ADM1031_REG_TEMP_MIN(chan)); - data->temp_max[chan] = adm1031_read_value(client, - ADM1031_REG_TEMP_MAX(chan)); - data->temp_crit[chan] = adm1031_read_value(client, - ADM1031_REG_TEMP_CRIT(chan)); - data->auto_temp[chan] = adm1031_read_value(client, - ADM1031_REG_AUTO_TEMP(chan)); - } - - data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1); - - data->alarms = adm1031_read_value(client, ADM1031_REG_STATUS(0)) - | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) - << 8); - if (data->chip_type == adm1030) { - data->alarms &= 0xc0ff; - } - - for (chan = 0; - chan < (data->chip_type == adm1030 ? 1 : 2); - chan++) { - data->fan_div[chan] = adm1031_read_value(client, - ADM1031_REG_FAN_DIV(chan)); - data->fan_min[chan] = adm1031_read_value(client, - ADM1031_REG_FAN_MIN(chan)); - data->fan[chan] = adm1031_read_value(client, - ADM1031_REG_FAN_SPEED(chan)); - data->fan_pwm[chan] = (adm1031_read_value(client, - ADM1031_REG_FAN_PWM) >> (4 * chan)) - & 0x0f; - } - - data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1); - data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -static int __init sensors_adm1031_init(void) -{ - printk(KERN_INFO "adm1031.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&adm1031_driver); -} - -static void __exit sensors_adm1031_exit(void) -{ - i2c_del_driver(&adm1031_driver); -} - - -static void -adm1031_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int ext; - struct adm1031_data *data = client->data; - int tmp; - int nr = ctl_name - ADM1031_SYSCTL_TEMP1; - - ext = nr == 0 ? - ((data->ext_temp[nr] >> 6) & 0x3) * 2 : - (((data->ext_temp[nr] >> ((nr - 1) * 3)) & 7)); - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1031_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_max[nr]); - results[1] = TEMP_FROM_REG(data->temp_min[nr]); - results[2] = TEMP_FROM_REG(data->temp_crit[nr]); - results[3] = TEMP_FROM_REG_EXT(data->temp[nr], ext); - *nrels_mag = 4; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - tmp = SENSORS_LIMIT(results[0], -55000, 127000); - data->temp_max[nr] = TEMP_TO_REG(tmp); - adm1031_write_value(client, - ADM1031_REG_TEMP_MAX(nr), - data->temp_max[nr]); - } - if (*nrels_mag >= 2) { - tmp = SENSORS_LIMIT(results[1], -55000, 127000); - data->temp_min[nr] = TEMP_TO_REG(tmp); - adm1031_write_value(client, - ADM1031_REG_TEMP_MIN(nr), - data->temp_min[nr]); - } - if (*nrels_mag >= 3) { - tmp = SENSORS_LIMIT(results[2], -55000, 127000); - data->temp_crit[nr] = TEMP_TO_REG(tmp); - adm1031_write_value(client, - ADM1031_REG_TEMP_CRIT(nr), - data->temp_crit[nr]); - } - } -} - -/* - * That function checks the cases where the fan reading is not - * relevant. It is used to provide 0 as fan reading when the fan is - * not supposed to run. - */ -static int trust_fan_readings(struct adm1031_data * data, int chan) -{ - int res = 0; - - if (data->conf1 & ADM1031_CONF1_AUTO_MODE) { - switch(data->conf1 & 0x60) { - case 0x00: /* temp2 controls fan1, temp3 controls fan2 */ - res = data->temp[chan+1] >= - AUTO_TEMP_MIN_FROM_REG(data->auto_temp[chan+1]); - break; - case 0x20: /* temp2 controls both fans */ - res = data->temp[1] >= - AUTO_TEMP_MIN_FROM_REG(data->auto_temp[1]); - break; - case 0x40: /* temp3 controls both fans */ - res = data->temp[2] >= - AUTO_TEMP_MIN_FROM_REG(data->auto_temp[2]); - break; - case 0x60: /* max of temp1, temp2 and temp3 controls both - fans */ - res = data->temp[0] >= - AUTO_TEMP_MIN_FROM_REG(data->auto_temp[0]) - || data->temp[1] >= - AUTO_TEMP_MIN_FROM_REG(data->auto_temp[1]) - || (data->chip_type == adm1031 - && data->temp[2] >= - AUTO_TEMP_MIN_FROM_REG(data->auto_temp[2])); - break; - } - } else { - res = data->fan_pwm[chan] > 0; - } - - return res; -} - -static void adm1031_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm1031_data *data = client->data; - int nr = ctl_name - ADM1031_SYSCTL_FAN1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1031_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr], - FAN_DIV_FROM_REG(data->fan_div[nr])); - results[1] = trust_fan_readings(data, nr) ? - FAN_FROM_REG(data->fan[nr], - FAN_DIV_FROM_REG(data->fan_div[nr])) : 0; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr] = FAN_TO_REG(results[0], - FAN_DIV_FROM_REG(data->fan_div[nr])); - adm1031_write_value(client, - ADM1031_REG_FAN_MIN(nr), - data->fan_min[nr]); - } - } -} - -static void adm1031_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm1031_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1031_update_client(client); - results[0] = FAN_DIV_FROM_REG(data->fan_div[0]); - *nrels_mag = 1; - if(data->chip_type == adm1031) { - results[1] = FAN_DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } - } else if (operation == SENSORS_PROC_REAL_WRITE) { - int old_div, new_min; - if (*nrels_mag >= 1) { - old_div = FAN_DIV_FROM_REG(data->fan_div[0]); - data->fan_div[0] = FAN_DIV_TO_REG(results[0]); - adm1031_write_value(client, - ADM1031_REG_FAN_DIV(0), - data->fan_div[0]); - new_min = data->fan_min[0] * old_div / - FAN_DIV_FROM_REG(data->fan_div[0]); - data->fan_min[0] = new_min > 0xff ? 0xff : new_min; - adm1031_write_value(client, - ADM1031_REG_FAN_MIN(0), - data->fan_min[0]); - } - if (*nrels_mag >= 2) { - old_div = FAN_DIV_FROM_REG(data->fan_div[1]); - data->fan_div[1] = FAN_DIV_TO_REG(results[1]); - adm1031_write_value(client, - ADM1031_REG_FAN_DIV(1), - data->fan_div[1]); - new_min = data->fan_min[1] * old_div / - FAN_DIV_FROM_REG(data->fan_div[1]); - data->fan_min[1] = new_min > 0xff ? 0xff : new_min; - adm1031_write_value(client, - ADM1031_REG_FAN_MIN(1), - data->fan_min[1]); - } - } -} - -static void adm1031_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm1031_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1031_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -MODULE_AUTHOR("Alexandre d'Alton "); -MODULE_DESCRIPTION("ADM1031/ADM1030 driver"); -MODULE_LICENSE("GPL"); - -module_init(sensors_adm1031_init); -module_exit(sensors_adm1031_exit); diff --git a/kernel/chips/adm9240.c b/kernel/chips/adm9240.c deleted file mode 100644 index 27110295..00000000 --- a/kernel/chips/adm9240.c +++ /dev/null @@ -1,700 +0,0 @@ -/* - adm9240.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (C) 1999 Frodo Looijaard - and Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* Supports ADM9240, DS1780, and LM81. See doc/chips/adm9240 for details */ - -/* - A couple notes about the ADM9240: - -* It claims to be 'LM7x' register compatible. This must be in reference - to only the LM78, because it is missing stuff to emulate LM75's as well. - (like the Winbond W83781 does) - -* This driver was written from rev. 0 of the PDF, but it seems well - written and complete (unlike the W83781 which is horrible and has - supposedly gone through a few revisions.. rev 0 of that one must - have been in crayon on construction paper...) - -* All analog inputs can range from 0 to 2.5, eventhough some inputs are - marked as being 5V, 12V, etc. I don't have any real voltages going - into my prototype, so I'm not sure that things are computed right, - but at least the limits seem to be working OK. - -* Another curiousity is that the fan_div seems to be read-only. I.e., - any written value to it doesn't seem to make any difference. The - fan_div seems to be 'stuck' at 2 (which isn't a bad value in most cases). - - --Phil -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x2c, 0x2f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_3(adm9240, ds1780, lm81); - -/* Many ADM9240 constants specified below */ - -#define ADM9240_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define ADM9240_REG_IN_MIN(nr) (0x2c + (nr) * 2) -#define ADM9240_REG_IN(nr) (0x20 + (nr)) - -/* The ADM9240 registers */ -#define ADM9240_REG_TEST 0x15 -#define ADM9240_REG_ANALOG_OUT 0x19 -/* These are all read-only */ -#define ADM9240_REG_2_5V 0x20 -#define ADM9240_REG_VCCP1 0x21 -#define ADM9240_REG_3_3V 0x22 -#define ADM9240_REG_5V 0x23 -#define ADM9240_REG_12V 0x24 -#define ADM9240_REG_VCCP2 0x25 -#define ADM9240_REG_TEMP 0x27 -#define ADM9240_REG_FAN1 0x28 -#define ADM9240_REG_FAN2 0x29 -#define ADM9240_REG_COMPANY_ID 0x3E /* 0x23 for ADM9240; 0xDA for DS1780 */ - /* 0x01 for LM81 */ -#define ADM9240_REG_DIE_REV 0x3F -/* These are read/write */ -#define ADM9240_REG_2_5V_HIGH 0x2B -#define ADM9240_REG_2_5V_LOW 0x2C -#define ADM9240_REG_VCCP1_HIGH 0x2D -#define ADM9240_REG_VCCP1_LOW 0x2E -#define ADM9240_REG_3_3V_HIGH 0x2F -#define ADM9240_REG_3_3V_LOW 0x30 -#define ADM9240_REG_5V_HIGH 0x31 -#define ADM9240_REG_5V_LOW 0x32 -#define ADM9240_REG_12V_HIGH 0x33 -#define ADM9240_REG_12V_LOW 0x34 -#define ADM9240_REG_VCCP2_HIGH 0x35 -#define ADM9240_REG_VCCP2_LOW 0x36 -#define ADM9240_REG_TCRIT_LIMIT 0x37 /* LM81 only - not supported */ -#define ADM9240_REG_LOW_LIMIT 0x38 /* LM81 only - not supported */ -#define ADM9240_REG_TOS 0x39 -#define ADM9240_REG_THYST 0x3A -#define ADM9240_REG_FAN1_MIN 0x3B -#define ADM9240_REG_FAN2_MIN 0x3C - -#define ADM9240_REG_CONFIG 0x40 -#define ADM9240_REG_INT1_STAT 0x41 -#define ADM9240_REG_INT2_STAT 0x42 -#define ADM9240_REG_INT1_MASK 0x43 -#define ADM9240_REG_INT2_MASK 0x44 - -#define ADM9240_REG_COMPAT 0x45 /* dummy compat. register for other drivers? */ -#define ADM9240_REG_CHASSIS_CLEAR 0x46 -#define ADM9240_REG_VID_FAN_DIV 0x47 -#define ADM9240_REG_I2C_ADDR 0x48 -#define ADM9240_REG_VID4 0x49 -#define ADM9240_REG_TEMP_CONFIG 0x4B -#define ADM9240_REG_EXTMODE1 0x4C /* LM81 only - not supported */ -#define ADM9240_REG_EXTMODE2 0x4D /* LM81 only - not supported */ - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val,nr) (SENSORS_LIMIT((val), 0, 255)) -#define IN_FROM_REG(val,nr) (val) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:\ - (val)==255?0:1350000/((div)*(val))) - -#define TEMP_FROM_REG(temp) ((temp)<256 ? (temp) * 5 : \ - ((temp) - 512) * 5) - -#define TEMP_LIMIT_FROM_REG(val) (((val)>=0x80?(val)-0x100:(val))*10) - -#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT(((val)<0?(((val)-5)/10)+256:\ - ((val)+5)/10), \ - 0,255) - -#define ALARMS_FROM_REG(val) (val) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==1?0:((val)==8?3:((val)==4?2:1))) - -#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ - 205-(val)*5) - -/* For each registered ADM9240, we need to keep some data in memory. */ -struct adm9240_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[6]; /* Register value */ - u8 in_max[6]; /* Register value */ - u8 in_min[6]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - int temp; /* Temp, shifted right */ - u8 temp_os_max; /* Register value */ - u8 temp_os_hyst; /* Register value */ - u16 alarms; /* Register encoding, combined */ - u8 analog_out; /* Register value */ - u8 vid; /* Register value combined */ -}; - - -static int adm9240_attach_adapter(struct i2c_adapter *adapter); -static int adm9240_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int adm9240_detach_client(struct i2c_client *client); - -static void adm9240_update_client(struct i2c_client *client); -static void adm9240_init_client(struct i2c_client *client); - - -static void adm9240_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm9240_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm9240_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm9240_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm9240_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm9240_analog_out(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, - long *results); -static void adm9240_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver adm9240_driver = { - .name = "ADM9240 sensor driver", - .id = I2C_DRIVERID_ADM9240, - .flags = I2C_DF_NOTIFY, - .attach_adapter = adm9240_attach_adapter, - .detach_client = adm9240_detach_client, -}; - -/* The /proc/sys entries */ - -/* -- SENSORS SYSCTL START -- */ - -#define ADM9240_SYSCTL_IN0 1000 /* Volts * 100 */ -#define ADM9240_SYSCTL_IN1 1001 -#define ADM9240_SYSCTL_IN2 1002 -#define ADM9240_SYSCTL_IN3 1003 -#define ADM9240_SYSCTL_IN4 1004 -#define ADM9240_SYSCTL_IN5 1005 -#define ADM9240_SYSCTL_FAN1 1101 /* Rotations/min */ -#define ADM9240_SYSCTL_FAN2 1102 -#define ADM9240_SYSCTL_TEMP 1250 /* Degrees Celsius * 100 */ -#define ADM9240_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define ADM9240_SYSCTL_ALARMS 2001 /* bitvector */ -#define ADM9240_SYSCTL_ANALOG_OUT 2002 -#define ADM9240_SYSCTL_VID 2003 - -#define ADM9240_ALARM_IN0 0x0001 -#define ADM9240_ALARM_IN1 0x0002 -#define ADM9240_ALARM_IN2 0x0004 -#define ADM9240_ALARM_IN3 0x0008 -#define ADM9240_ALARM_IN4 0x0100 -#define ADM9240_ALARM_IN5 0x0200 -#define ADM9240_ALARM_FAN1 0x0040 -#define ADM9240_ALARM_FAN2 0x0080 -#define ADM9240_ALARM_TEMP 0x0010 -#define ADM9240_ALARM_CHAS 0x1000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected ADM9240. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table adm9240_dir_table_template[] = { - {ADM9240_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_in}, - {ADM9240_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_in}, - {ADM9240_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_in}, - {ADM9240_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_in}, - {ADM9240_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_in}, - {ADM9240_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_in}, - {ADM9240_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_fan}, - {ADM9240_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_fan}, - {ADM9240_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_temp}, - {ADM9240_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_fan_div}, - {ADM9240_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_alarms}, - {ADM9240_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_analog_out}, - {ADM9240_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm9240_vid}, - {0} -}; - -static int adm9240_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, adm9240_detect); -} - -static int adm9240_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct adm9240_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access adm9240_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct adm9240_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &adm9240_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if ( - ((i2c_smbus_read_byte_data - (new_client, ADM9240_REG_CONFIG) & 0x80) != 0x00) - || - (i2c_smbus_read_byte_data(new_client, ADM9240_REG_I2C_ADDR) - != address)) - goto ERROR1; - } - - /* Determine the chip type. */ - if (kind <= 0) { - i = i2c_smbus_read_byte_data(new_client, - ADM9240_REG_COMPANY_ID); - if (i == 0x23) - kind = adm9240; - else if (i == 0xda) - kind = ds1780; - else if (i == 0x01) - kind = lm81; - else { - if (kind == 0) - printk("adm9240.o: Ignoring 'force' " - "parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - goto ERROR1; - } - } - - if (kind == adm9240) { - type_name = "adm9240"; - client_name = "ADM9240 chip"; - } else if (kind == ds1780) { - type_name = "ds1780"; - client_name = "DS1780 chip"; - } else if (kind == lm81) { - type_name = "lm81"; - client_name = "LM81 chip"; - } else { -#ifdef DEBUG - printk("adm9240.o: Internal error: unknown kind (%d)?!?", - kind); -#endif - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global - list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - adm9240_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the ADM9240 chip */ - adm9240_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int adm9240_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct adm9240_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("adm9240.o: Client deregistration failed, " - "client not detached\n"); - return err; - } - - kfree(client->data); - - return 0; -} - - -/* Called when we have found a new ADM9240. */ -static void adm9240_init_client(struct i2c_client *client) -{ - /* Start monitoring */ - i2c_smbus_write_byte_data(client, ADM9240_REG_CONFIG, 0x01); -} - -static void adm9240_update_client(struct i2c_client *client) -{ - struct adm9240_data *data = client->data; - u8 i; - - down(&data->update_lock); - - if ( - (jiffies - data->last_updated > - (data->type == adm9240 ? HZ / 2 : HZ * 2)) - || (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting adm9240 update\n"); -#endif - for (i = 0; i <= 5; i++) { - data->in[i] = - i2c_smbus_read_byte_data(client, - ADM9240_REG_IN(i)); - data->in_min[i] = - i2c_smbus_read_byte_data(client, - ADM9240_REG_IN_MIN(i)); - data->in_max[i] = - i2c_smbus_read_byte_data(client, - ADM9240_REG_IN_MAX(i)); - } - data->fan[0] = - i2c_smbus_read_byte_data(client, ADM9240_REG_FAN1); - data->fan_min[0] = - i2c_smbus_read_byte_data(client, ADM9240_REG_FAN1_MIN); - data->fan[1] = - i2c_smbus_read_byte_data(client, ADM9240_REG_FAN2); - data->fan_min[1] = - i2c_smbus_read_byte_data(client, ADM9240_REG_FAN2_MIN); - data->temp = - (i2c_smbus_read_byte_data(client, ADM9240_REG_TEMP) << 1) + - ((i2c_smbus_read_byte_data - (client, ADM9240_REG_TEMP_CONFIG) & 0x80) >> 7); - data->temp_os_max = - i2c_smbus_read_byte_data(client, ADM9240_REG_TOS); - data->temp_os_hyst = - i2c_smbus_read_byte_data(client, ADM9240_REG_THYST); - - i = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - data->vid = i & 0x0f; - data->vid |= - (i2c_smbus_read_byte_data(client, ADM9240_REG_VID4) & 0x01) - << 4; - - data->alarms = - i2c_smbus_read_byte_data(client, - ADM9240_REG_INT1_STAT) + - (i2c_smbus_read_byte_data(client, ADM9240_REG_INT2_STAT) << - 8); - data->analog_out = - i2c_smbus_read_byte_data(client, ADM9240_REG_ANALOG_OUT); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void adm9240_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - - int scales[6] = { 250, 270, 330, 500, 1200, 270 }; - - struct adm9240_data *data = client->data; - int nr = ctl_name - ADM9240_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = - IN_FROM_REG(data->in_min[nr], nr) * scales[nr] / 192; - results[1] = - IN_FROM_REG(data->in_max[nr], nr) * scales[nr] / 192; - results[2] = - IN_FROM_REG(data->in[nr], nr) * scales[nr] / 192; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = - IN_TO_REG((results[0] * 192) / scales[nr], nr); - i2c_smbus_write_byte_data(client, - ADM9240_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = - IN_TO_REG((results[1] * 192) / scales[nr], nr); - i2c_smbus_write_byte_data(client, - ADM9240_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void adm9240_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - int nr = ctl_name - ADM9240_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data-> - fan_div[nr - 1])); - results[1] = - FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = FAN_TO_REG(results[0], - DIV_FROM_REG - (data-> - fan_div[nr - - 1])); - i2c_smbus_write_byte_data(client, nr == 1 ? - ADM9240_REG_FAN1_MIN : - ADM9240_REG_FAN2_MIN, - data->fan_min[nr - 1]); - } - } -} - - -void adm9240_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = TEMP_LIMIT_FROM_REG(data->temp_os_max); - results[1] = TEMP_LIMIT_FROM_REG(data->temp_os_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_os_max = TEMP_LIMIT_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, ADM9240_REG_TOS, - data->temp_os_max); - } - if (*nrels_mag >= 2) { - data->temp_os_hyst = TEMP_LIMIT_TO_REG(results[1]); - i2c_smbus_write_byte_data(client, ADM9240_REG_THYST, - data->temp_os_hyst); - } - } -} - -void adm9240_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void adm9240_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = i2c_smbus_read_byte_data(client, - ADM9240_REG_VID_FAN_DIV); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan_div[1] << 6); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div[0] << 4); - i2c_smbus_write_byte_data(client, - ADM9240_REG_VID_FAN_DIV, - old); - } - } -} - -void adm9240_analog_out(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = data->analog_out; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->analog_out = results[0]; - i2c_smbus_write_byte_data(client, - ADM9240_REG_ANALOG_OUT, - data->analog_out); - } - } -} - -void adm9240_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = VID_FROM_REG(data->vid); - *nrels_mag = 1; - } -} - -static int __init sm_adm9240_init(void) -{ - printk("adm9240.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&adm9240_driver); -} - -static void __exit sm_adm9240_exit(void) -{ - i2c_del_driver(&adm9240_driver); -} - - -MODULE_AUTHOR("Frodo Looijaard " - "and Philip Edelbrock "); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("ADM9240 driver"); - -module_init(sm_adm9240_init); -module_exit(sm_adm9240_exit); diff --git a/kernel/chips/asb100.c b/kernel/chips/asb100.c deleted file mode 100644 index 824bc64b..00000000 --- a/kernel/chips/asb100.c +++ /dev/null @@ -1,1017 +0,0 @@ -/* - asb100.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - - Copyright (c) 2003 Mark M. Hoffman - - (derived from w83781d.c) - - Copyright (c) 1998 - 2003 Frodo Looijaard , - Philip Edelbrock , and - Mark Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - This driver supports the hardware sensor chips: Asus ASB100 and - ASB100-A "BACH". - - ASB100-A supports pwm1, while plain ASB100 does not. There is no known - way for the driver to tell which one is there. - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - asb100 7 3 1 4 0x31 0x0694 yes no -*/ - -//#define DEBUG 1 - -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" -#include "lm75.h" - -#ifndef I2C_DRIVERID_ASB100 -#define I2C_DRIVERID_ASB100 1043 -#endif - -/* I2C addresses to scan */ -static unsigned short normal_i2c[] = { 0x2d, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; - -/* ISA addresses to scan (none) */ -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* default VRM to 9.0 */ -#define ASB100_DEFAULT_VRM 90 - -/* Insmod parameters */ -SENSORS_INSMOD_1(asb100); -SENSORS_MODULE_PARM(force_subclients, "List of subclient addresses: " \ - "{bus, clientaddr, subclientaddr1, subclientaddr2}"); - -/* Voltage IN registers 0-6 */ -#define ASB100_REG_IN(nr) (0x20 + (nr)) -#define ASB100_REG_IN_MAX(nr) (0x2b + (nr * 2)) -#define ASB100_REG_IN_MIN(nr) (0x2c + (nr * 2)) - -/* FAN IN registers 1-3 */ -#define ASB100_REG_FAN(nr) (0x27 + (nr)) -#define ASB100_REG_FAN_MIN(nr) (0x3a + (nr)) - -/* TEMPERATURE registers 1-4 */ -static const u16 asb100_reg_temp[] = {0, 0x27, 0x150, 0x250, 0x17}; -static const u16 asb100_reg_temp_max[] = {0, 0x39, 0x155, 0x255, 0x18}; -static const u16 asb100_reg_temp_hyst[] = {0, 0x3a, 0x153, 0x253, 0x19}; - -#define ASB100_REG_TEMP(nr) (asb100_reg_temp[nr]) -#define ASB100_REG_TEMP_MAX(nr) (asb100_reg_temp_max[nr]) -#define ASB100_REG_TEMP_HYST(nr) (asb100_reg_temp_hyst[nr]) - -#define ASB100_REG_TEMP2_CONFIG 0x0152 -#define ASB100_REG_TEMP3_CONFIG 0x0252 - - -#define ASB100_REG_CONFIG 0x40 -#define ASB100_REG_ALARM1 0x41 -#define ASB100_REG_ALARM2 0x42 -#define ASB100_REG_SMIM1 0x43 -#define ASB100_REG_SMIM2 0x44 -#define ASB100_REG_VID_FANDIV 0x47 -#define ASB100_REG_I2C_ADDR 0x48 -#define ASB100_REG_CHIPID 0x49 -#define ASB100_REG_I2C_SUBADDR 0x4a -#define ASB100_REG_PIN 0x4b -#define ASB100_REG_IRQ 0x4c -#define ASB100_REG_BANK 0x4e -#define ASB100_REG_CHIPMAN 0x4f - -#define ASB100_REG_WCHIPID 0x58 - -/* bit 7 -> enable, bits 0-3 -> duty cycle */ -#define ASB100_REG_PWM1 0x59 - -/* CONVERSIONS - Rounding and limit checking is only done on the TO_REG variants. */ - -/* These constants are a guess, consistent w/ w83781d */ -#define ASB100_IN_MIN ( 0) -#define ASB100_IN_MAX (408) - -/* IN: 1/100 V (0V to 4.08V) - REG: 16mV/bit */ -static u8 IN_TO_REG(unsigned val) -{ - unsigned nval = SENSORS_LIMIT(val, ASB100_IN_MIN, ASB100_IN_MAX); - return (nval * 10 + 8) / 16; -} - -static unsigned IN_FROM_REG(u8 reg) -{ - return (reg * 16 + 5) / 10; -} - -static u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); -} - -static int FAN_FROM_REG(u8 val, int div) -{ - return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); -} - -/* These constants are a guess, consistent w/ w83781d */ -#define ASB100_TEMP_MIN (-1280) -#define ASB100_TEMP_MAX ( 1270) - -/* TEMP: 1/10 degrees C (-128C to +127C) - REG: 1C/bit, two's complement */ -static u8 TEMP_TO_REG(int temp) -{ - int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX); - ntemp += (ntemp<0 ? -5 : 5); - return (u8)(ntemp / 10); -} - -static int TEMP_FROM_REG(u8 reg) -{ - return (s8)reg * 10; -} - -/* PWM: 0 - 255 per sensors documentation - REG: (6.25% duty cycle per bit) */ -static u8 ASB100_PWM_TO_REG(int pwm) -{ - pwm = SENSORS_LIMIT(pwm, 0, 255); - return (u8)(pwm / 16); -} - -static int ASB100_PWM_FROM_REG(u8 reg) -{ - return reg * 16; -} - -#define ALARMS_FROM_REG(val) (val) - -#define DIV_FROM_REG(val) (1 << (val)) - -/* FAN DIV: 1, 2, 4, or 8 (defaults to 2) - REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */ -static u8 DIV_TO_REG(long val) -{ - return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1; -} - -/* For each registered client, we need to keep some data in memory. That - data is pointed to by client->data. The structure itself is - dynamically allocated, at the same time the client itself is allocated. */ -struct asb100_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - unsigned long last_updated; /* In jiffies */ - - /* array of 2 pointers to subclients */ - struct i2c_client *lm75[2]; - - char valid; /* !=0 if following fields are valid */ - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u16 temp[4]; /* Register value (0 and 3 are u8 only) */ - u16 temp_max[4]; /* Register value (0 and 3 are u8 only) */ - u16 temp_hyst[4]; /* Register value (0 and 3 are u8 only) */ - u8 fan_div[3]; /* Register encoding, right justified */ - u8 pwm; /* Register encoding */ - u8 vid; /* Register encoding, combined */ - u32 alarms; /* Register encoding, combined */ - u8 vrm; -}; - -static int asb100_attach_adapter(struct i2c_adapter *adapter); -static int asb100_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int asb100_detach_client(struct i2c_client *client); - -static int asb100_read_value(struct i2c_client *client, u16 reg); -static void asb100_write_value(struct i2c_client *client, u16 reg, u16 val); -static void asb100_update_client(struct i2c_client *client); -static void asb100_init_client(struct i2c_client *client); - -static void asb100_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void asb100_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void asb100_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void asb100_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void asb100_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void asb100_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void asb100_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void asb100_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void asb100_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver asb100_driver = { - .name = "asb100", - .id = I2C_DRIVERID_ASB100, - .flags = I2C_DF_NOTIFY, - .attach_adapter = asb100_attach_adapter, - .detach_client = asb100_detach_client, -}; - -/* The /proc/sys entries */ -/* -- SENSORS SYSCTL START -- */ - -#define ASB100_SYSCTL_IN0 1000 /* Volts * 100 */ -#define ASB100_SYSCTL_IN1 1001 -#define ASB100_SYSCTL_IN2 1002 -#define ASB100_SYSCTL_IN3 1003 -#define ASB100_SYSCTL_IN4 1004 -#define ASB100_SYSCTL_IN5 1005 -#define ASB100_SYSCTL_IN6 1006 - -#define ASB100_SYSCTL_FAN1 1101 /* Rotations/min */ -#define ASB100_SYSCTL_FAN2 1102 -#define ASB100_SYSCTL_FAN3 1103 - -#define ASB100_SYSCTL_TEMP1 1200 /* Degrees Celsius * 10 */ -#define ASB100_SYSCTL_TEMP2 1201 -#define ASB100_SYSCTL_TEMP3 1202 -#define ASB100_SYSCTL_TEMP4 1203 - -#define ASB100_SYSCTL_VID 1300 /* Volts * 1000 */ -#define ASB100_SYSCTL_VRM 1301 - -#define ASB100_SYSCTL_PWM1 1401 /* 0-255 => 0-100% duty cycle */ - -#define ASB100_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define ASB100_SYSCTL_ALARMS 2001 /* bitvector */ - -#define ASB100_ALARM_IN0 0x0001 /* ? */ -#define ASB100_ALARM_IN1 0x0002 /* ? */ -#define ASB100_ALARM_IN2 0x0004 -#define ASB100_ALARM_IN3 0x0008 -#define ASB100_ALARM_TEMP1 0x0010 -#define ASB100_ALARM_TEMP2 0x0020 -#define ASB100_ALARM_FAN1 0x0040 -#define ASB100_ALARM_FAN2 0x0080 -#define ASB100_ALARM_IN4 0x0100 -#define ASB100_ALARM_IN5 0x0200 /* ? */ -#define ASB100_ALARM_IN6 0x0400 /* ? */ -#define ASB100_ALARM_FAN3 0x0800 -#define ASB100_ALARM_CHAS 0x1000 -#define ASB100_ALARM_TEMP3 0x2000 - -#define ASB100_ALARM_IN7 0x10000 /* ? */ -#define ASB100_ALARM_IN8 0x20000 /* ? */ - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected chip. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ - -/* no datasheet - but we did get some hints from someone who - claimed to have the datasheet */ -#define ASB100_SYSCTL_IN(nr) {ASB100_SYSCTL_IN##nr, "in" #nr, NULL, 0, \ - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &asb100_in} -#define ASB100_SYSCTL_FAN(nr) {ASB100_SYSCTL_FAN##nr, "fan" #nr, NULL, 0, \ - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &asb100_fan} -#define ASB100_SYSCTL_TEMP(nr, func) {ASB100_SYSCTL_TEMP##nr, "temp" #nr, \ - NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, func} -static ctl_table asb100_dir_table_template[] = { - ASB100_SYSCTL_IN(0), - ASB100_SYSCTL_IN(1), - ASB100_SYSCTL_IN(2), - ASB100_SYSCTL_IN(3), - ASB100_SYSCTL_IN(4), - ASB100_SYSCTL_IN(5), - ASB100_SYSCTL_IN(6), - - ASB100_SYSCTL_FAN(1), - ASB100_SYSCTL_FAN(2), - ASB100_SYSCTL_FAN(3), - - ASB100_SYSCTL_TEMP(1, &asb100_temp), - ASB100_SYSCTL_TEMP(2, &asb100_temp_add), - ASB100_SYSCTL_TEMP(3, &asb100_temp_add), - ASB100_SYSCTL_TEMP(4, &asb100_temp), - - {ASB100_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &asb100_vid}, - {ASB100_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &asb100_vrm}, - {ASB100_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &asb100_fan_div}, - {ASB100_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &asb100_alarms}, - {ASB100_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &asb100_pwm}, - {0} -}; - -/* This function is called when: - asb100_driver is inserted (when this module is loaded), for each - available adapter - when a new adapter is inserted (and asb100_driver is still present) - */ -static int asb100_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, asb100_detect); -} - -static int asb100_detect_subclients(struct i2c_adapter *adapter, int address, - int kind, struct i2c_client *new_client) -{ - int i, id, err = 0; - struct asb100_data *data = new_client->data; - - data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!(data->lm75[0])) { - err = -ENOMEM; - goto ERROR_SC_0; - } - memset(data->lm75[0], 0x00, sizeof(struct i2c_client)); - - data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!(data->lm75[1])) { - err = -ENOMEM; - goto ERROR_SC_1; - } - memset(data->lm75[1], 0x00, sizeof(struct i2c_client)); - - id = i2c_adapter_id(adapter); - - if (force_subclients[0] == id && force_subclients[1] == address) { - for (i = 2; i <= 3; i++) { - if (force_subclients[i] < 0x48 || - force_subclients[i] > 0x4f) { - printk(KERN_ERR "asb100.o: invalid subclient " - "address %d; must be 0x48-0x4f\n", - force_subclients[i]); - goto ERROR_SC_2; - } - } - asb100_write_value(new_client, ASB100_REG_I2C_SUBADDR, - (force_subclients[2] & 0x07) | - ((force_subclients[3] & 0x07) <<4)); - data->lm75[0]->addr = force_subclients[2]; - data->lm75[1]->addr = force_subclients[3]; - } else { - int val = asb100_read_value(new_client, ASB100_REG_I2C_SUBADDR); - data->lm75[0]->addr = 0x48 + (val & 0x07); - data->lm75[1]->addr = 0x48 + ((val >> 4) & 0x07); - } - - if(data->lm75[0]->addr == data->lm75[1]->addr) { - printk(KERN_ERR "asb100.o: duplicate addresses 0x%x " - "for subclients\n", data->lm75[0]->addr); - goto ERROR_SC_2; - } - - for (i = 0; i <= 1; i++) { - data->lm75[i]->data = NULL; - data->lm75[i]->adapter = adapter; - data->lm75[i]->driver = &asb100_driver; - data->lm75[i]->flags = 0; - strcpy(data->lm75[i]->name, "asb100 subclient"); - } - - if ((err = i2c_attach_client(data->lm75[0]))) { - printk(KERN_ERR "asb100.o: Subclient %d registration " - "at address 0x%x failed.\n", i, data->lm75[0]->addr); - goto ERROR_SC_2; - } - - if ((err = i2c_attach_client(data->lm75[1]))) { - printk(KERN_ERR "asb100.o: Subclient %d registration " - "at address 0x%x failed.\n", i, data->lm75[1]->addr); - goto ERROR_SC_3; - } - - return 0; - -/* Undo inits in case of errors */ -ERROR_SC_3: - i2c_detach_client(data->lm75[0]); -ERROR_SC_2: - kfree(data->lm75[1]); -ERROR_SC_1: - kfree(data->lm75[0]); -ERROR_SC_0: - return err; -} - -static int asb100_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int err = 0; - struct i2c_client *new_client; - struct asb100_data *data; - - /* asb100 is SMBus only */ - if (i2c_is_isa_adapter(adapter)) { - pr_debug("asb100.o: detect failed, " - "cannot attach to legacy adapter!\n"); - goto ERROR0; - } - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - pr_debug("asb100.o: detect failed, " - "smbus byte data not supported!\n"); - goto ERROR0; - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access asb100_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct asb100_data), GFP_KERNEL))) { - pr_debug("asb100.o: detect failed, kmalloc failed!\n"); - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &asb100_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - /* The chip may be stuck in some other bank than bank 0. This may - make reading other information impossible. Specify a force=... or - force_*=... parameter, and the chip will be reset to the right - bank. */ - if (kind < 0) { - - int val1 = asb100_read_value(new_client, ASB100_REG_BANK); - int val2 = asb100_read_value(new_client, ASB100_REG_CHIPMAN); - - /* If we're in bank 0 */ - if ( (!(val1 & 0x07)) && - /* Check for ASB100 ID (low byte) */ - ( ((!(val1 & 0x80)) && (val2 != 0x94)) || - /* Check for ASB100 ID (high byte ) */ - ((val1 & 0x80) && (val2 != 0x06)) ) ) { - pr_debug("asb100.o: detect failed, " - "bad chip id 0x%02x!\n", val2); - goto ERROR1; - } - - } /* kind < 0 */ - - /* We have either had a force parameter, or we have already detected - Winbond. Put it now into bank 0 and Vendor ID High Byte */ - asb100_write_value(new_client, ASB100_REG_BANK, - (asb100_read_value(new_client, ASB100_REG_BANK) & 0x78) | 0x80); - - /* Determine the chip type. */ - if (kind <= 0) { - int val1 = asb100_read_value(new_client, ASB100_REG_WCHIPID); - int val2 = asb100_read_value(new_client, ASB100_REG_CHIPMAN); - - if ((val1 == 0x31) && (val2 == 0x06)) - kind = asb100; - else { - if (kind == 0) - printk (KERN_WARNING "asb100.o: Ignoring " - "'force' parameter for unknown chip " - "at adapter %d, address 0x%02x.\n", - i2c_adapter_id(adapter), address); - goto ERROR1; - } - } - - /* Fill in remaining client fields and put it into the global list */ - strcpy(new_client->name, "ASB100 chip"); - data->type = kind; - - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR1; - - /* Attach secondary lm75 clients */ - if ((err = asb100_detect_subclients(adapter, address, kind, - new_client))) - goto ERROR2; - - /* Initialize the chip */ - asb100_init_client(new_client); - - /* Register a new directory entry with module sensors */ - if ((data->sysctl_id = i2c_register_entry(new_client, "asb100", - asb100_dir_table_template, THIS_MODULE)) < 0) { - err = data->sysctl_id; - goto ERROR3; - } - - return 0; - -ERROR3: - i2c_detach_client(data->lm75[0]); - kfree(data->lm75[1]); - kfree(data->lm75[0]); -ERROR2: - i2c_detach_client(new_client); -ERROR1: - kfree(data); -ERROR0: - return err; -} - -static int asb100_detach_client(struct i2c_client *client) -{ - int err; - struct asb100_data *data = client->data; - - /* remove sysctl table (primary client only) */ - if ((data)) - i2c_deregister_entry(data->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk (KERN_ERR "asb100.o: Client deregistration failed; " - "client not detached.\n"); - return err; - } - - if (data) { - /* primary client */ - kfree(data); - } else { - /* subclients */ - kfree(client); - } - - return 0; -} - -/* The SMBus locks itself, usually, but nothing may access the Winbond between - bank switches. ISA access must always be locked explicitly! - We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, - would slow down the W83781D access and should not be necessary. - There are some ugly typecasts here, but the good news is - they should - nowhere else be necessary! */ -static int asb100_read_value(struct i2c_client *client, u16 reg) -{ - struct asb100_data *data = client->data; - struct i2c_client *cl; - int res, bank; - - down(&data->lock); - - bank = (reg >> 8) & 0x0f; - if (bank > 2) - /* switch banks */ - i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank); - - if (bank == 0 || bank > 2) { - res = i2c_smbus_read_byte_data(client, reg & 0xff); - } else { - /* switch to subclient */ - cl = data->lm75[bank - 1]; - - /* convert from ISA to LM75 I2C addresses */ - switch (reg & 0xff) { - case 0x50: /* TEMP */ - res = swab16(i2c_smbus_read_word_data (cl, 0)); - break; - case 0x52: /* CONFIG */ - res = i2c_smbus_read_byte_data(cl, 1); - break; - case 0x53: /* HYST */ - res = swab16(i2c_smbus_read_word_data (cl, 2)); - break; - case 0x55: /* MAX */ - default: - res = swab16(i2c_smbus_read_word_data (cl, 3)); - break; - } - } - - if (bank > 2) - i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0); - - up(&data->lock); - - return res; -} - -static void asb100_write_value(struct i2c_client *client, u16 reg, u16 value) -{ - struct asb100_data *data = client->data; - struct i2c_client *cl; - int bank; - - down(&data->lock); - - bank = (reg >> 8) & 0x0f; - if (bank > 2) - /* switch banks */ - i2c_smbus_write_byte_data(client, ASB100_REG_BANK, bank); - - if (bank == 0 || bank > 2) { - i2c_smbus_write_byte_data(client, reg & 0xff, value & 0xff); - } else { - /* switch to subclient */ - cl = data->lm75[bank - 1]; - - /* convert from ISA to LM75 I2C addresses */ - switch (reg & 0xff) { - case 0x52: /* CONFIG */ - i2c_smbus_write_byte_data(cl, 1, value & 0xff); - break; - case 0x53: /* HYST */ - i2c_smbus_write_word_data(cl, 2, swab16(value)); - break; - case 0x55: /* MAX */ - i2c_smbus_write_word_data(cl, 3, swab16(value)); - break; - } - } - - if (bank > 2) - i2c_smbus_write_byte_data(client, ASB100_REG_BANK, 0); - - up(&data->lock); -} - -static void asb100_init_client(struct i2c_client *client) -{ - struct asb100_data *data = client->data; - int vid = 0; - - vid = asb100_read_value(client, ASB100_REG_VID_FANDIV) & 0x0f; - vid |= (asb100_read_value(client, ASB100_REG_CHIPID) & 0x01) << 4; - data->vrm = ASB100_DEFAULT_VRM; - vid = vid_from_reg(vid, data->vrm); - - /* Start monitoring */ - asb100_write_value(client, ASB100_REG_CONFIG, - (asb100_read_value(client, ASB100_REG_CONFIG) & 0xf7) | 0x01); -} - -static void asb100_update_client(struct i2c_client *client) -{ - struct asb100_data *data = client->data; - int i; - - down(&data->update_lock); - - if (time_after(jiffies - data->last_updated, HZ + HZ / 2) || - time_before(jiffies, data->last_updated) || !data->valid) { - - pr_debug("asb100.o: starting device update...\n"); - - /* 7 voltage inputs */ - for (i = 0; i < 7; i++) { - data->in[i] = asb100_read_value(client, - ASB100_REG_IN(i)); - data->in_min[i] = asb100_read_value(client, - ASB100_REG_IN_MIN(i)); - data->in_max[i] = asb100_read_value(client, - ASB100_REG_IN_MAX(i)); - } - - /* 3 fan inputs */ - for (i = 1; i <= 3; i++) { - data->fan[i-1] = asb100_read_value(client, - ASB100_REG_FAN(i)); - data->fan_min[i-1] = asb100_read_value(client, - ASB100_REG_FAN_MIN(i)); - } - - /* 4 temperature inputs */ - for (i = 1; i <= 4; i++) { - data->temp[i-1] = asb100_read_value(client, - ASB100_REG_TEMP(i)); - data->temp_max[i-1] = asb100_read_value(client, - ASB100_REG_TEMP_MAX(i)); - data->temp_hyst[i-1] = asb100_read_value(client, - ASB100_REG_TEMP_HYST(i)); - } - - /* VID and fan divisors */ - i = asb100_read_value(client, ASB100_REG_VID_FANDIV); - data->vid = i & 0x0f; - data->vid |= (asb100_read_value(client, - ASB100_REG_CHIPID) & 0x01) << 4; - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - data->fan_div[2] = (asb100_read_value(client, - ASB100_REG_PIN) >> 6) & 0x03; - - /* PWM */ - data->pwm = asb100_read_value(client, ASB100_REG_PWM1); - - /* alarms */ - data->alarms = asb100_read_value(client, ASB100_REG_ALARM1) + - (asb100_read_value(client, ASB100_REG_ALARM2) << 8); - - data->last_updated = jiffies; - data->valid = 1; - - pr_debug("asb100.o: ... update complete.\n"); - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -static void asb100_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct asb100_data *data = client->data; - int nr = ctl_name - ASB100_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - asb100_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0]); - asb100_write_value(client, ASB100_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1]); - asb100_write_value(client, ASB100_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void asb100_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct asb100_data *data = client->data; - int nr = ctl_name - ASB100_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - asb100_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - results[1] = FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = - FAN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr-1])); - asb100_write_value(client, - ASB100_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } - } -} - -void asb100_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct asb100_data *data = client->data; - int nr = ctl_name - ASB100_SYSCTL_TEMP1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - - else if (operation == SENSORS_PROC_REAL_READ) { - asb100_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_max[nr]); - results[1] = TEMP_FROM_REG(data->temp_hyst[nr]); - results[2] = TEMP_FROM_REG(data->temp[nr]); - *nrels_mag = 3; - - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_max[nr] = TEMP_TO_REG(results[0]); - asb100_write_value(client, ASB100_REG_TEMP_MAX(nr+1), - data->temp_max[nr]); - } - if (*nrels_mag >= 2) { - data->temp_hyst[nr] = TEMP_TO_REG(results[1]); - asb100_write_value(client, ASB100_REG_TEMP_HYST(nr+1), - data->temp_hyst[nr]); - } - } -} - -void asb100_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct asb100_data *data = client->data; - int nr = ctl_name - ASB100_SYSCTL_TEMP1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - - else if (operation == SENSORS_PROC_REAL_READ) { - asb100_update_client(client); - - results[0] = LM75_TEMP_FROM_REG(data->temp_max[nr]); - results[1] = LM75_TEMP_FROM_REG(data->temp_hyst[nr]); - results[2] = LM75_TEMP_FROM_REG(data->temp[nr]); - *nrels_mag = 3; - - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_max[nr] = - LM75_TEMP_TO_REG(results[0]); - asb100_write_value(client, ASB100_REG_TEMP_MAX(nr+1), - data->temp_max[nr]); - } - if (*nrels_mag >= 2) { - data->temp_hyst[nr] = - LM75_TEMP_TO_REG(results[1]); - asb100_write_value(client, ASB100_REG_TEMP_HYST(nr+1), - data->temp_hyst[nr]); - } - } -} - -void asb100_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct asb100_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - asb100_update_client(client); - results[0] = vid_from_reg(data->vid, data->vrm); - *nrels_mag = 1; - } -} - -void asb100_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct asb100_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) - data->vrm = results[0]; - } -} - -void asb100_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct asb100_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - asb100_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void asb100_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct asb100_data *data = client->data; - int old, old2; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - - else if (operation == SENSORS_PROC_REAL_READ) { - asb100_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - results[2] = DIV_FROM_REG(data->fan_div[2]); - *nrels_mag = 3; - - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = asb100_read_value(client, ASB100_REG_VID_FANDIV); - if (*nrels_mag >= 3) { - data->fan_div[2] = DIV_TO_REG(results[2]); - old2 = asb100_read_value(client, ASB100_REG_PIN); - old2 = (old2 & 0x3f) | ((data->fan_div[2] & 0x03) << 6); - asb100_write_value(client, ASB100_REG_PIN, old2); - } - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | ((data->fan_div[1] & 0x03) << 6); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | ((data->fan_div[0] & 0x03) << 4); - asb100_write_value(client, ASB100_REG_VID_FANDIV, old); - } - } -} - -void asb100_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct asb100_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - asb100_update_client(client); - results[0] = ASB100_PWM_FROM_REG(data->pwm & 0x0f); - results[1] = (data->pwm & 0x80) ? 1 : 0; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - u8 val = data->pwm; - if (*nrels_mag >= 1) { - val = 0x0f & ASB100_PWM_TO_REG(results[0]); - if (*nrels_mag >= 2) { - if (results[1]) - val |= 0x80; - else - val &= ~0x80; - } - asb100_write_value(client, ASB100_REG_PWM1, val); - } - } -} - -static int __init asb100_init(void) -{ - printk(KERN_INFO "asb100.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&asb100_driver); -} - -static void __exit asb100_exit(void) -{ - i2c_del_driver(&asb100_driver); -} - -MODULE_AUTHOR( "Mark M. Hoffman , " - "Frodo Looijaard , " - "Philip Edelbrock , and " - "Mark Studebaker "); - -MODULE_DESCRIPTION("ASB100 'Bach' driver"); -MODULE_LICENSE("GPL"); - -module_init(asb100_init); -module_exit(asb100_exit); - diff --git a/kernel/chips/bmcsensors.c b/kernel/chips/bmcsensors.c deleted file mode 100644 index 00077e15..00000000 --- a/kernel/chips/bmcsensors.c +++ /dev/null @@ -1,1133 +0,0 @@ -/* - bmcsensors.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Copyright (c) 2002 Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -/* for kernel thread ... */ -#include -#include -#include -#include -#include "version.h" - -/* -#define DEBUG 1 -*/ - -struct bmcsensors_data { - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 alarms; -}; - - -static int bmcsensors_attach_adapter(struct i2c_adapter *adapter); -static int bmcsensors_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int bmcsensors_detach_client(struct i2c_client *client); -static int bmcsensors_command(struct i2c_client *client, unsigned int cmd, - void *arg); - -static void bmcsensors_update_client(struct i2c_client *client); -static void bmcsensors_reserve_sdr(void); -static void bmc_do_pause(unsigned int amount); /* YJ for debug */ - - -static void bmcsensors_all(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -#if 0 -static void bmcsensors_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void bmcsensors_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void bmcsensors_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -#endif -static void bmcsensors_get_sdr(u16 resid, u16 record, u8 offset); -static void bmcsensors_get_reading(struct i2c_client *client, int i); - -static struct i2c_driver bmcsensors_driver = { - .name = "BMC Sensors driver", - .id = I2C_DRIVERID_BMCSENSORS, - .flags = I2C_DF_NOTIFY, - .attach_adapter = bmcsensors_attach_adapter, - .detach_client = bmcsensors_detach_client, - .command = bmcsensors_command, -}; - -static struct bmcsensors_data bmc_data; -static struct i2c_client bmc_client = { - .name = "BMC Sensors", - .id = 1, /* fake should be 0 */ - .driver = &bmcsensors_driver, - .data = &bmc_data, -}; - -static int bmcsensors_initialized; - -#define MAX_SDR_ENTRIES 100 -#define SDR_LIMITS 8 -#define SDR_MAX_ID_LENGTH 16 -#define SDR_MAX_UNPACKED_ID_LENGTH ((SDR_MAX_ID_LENGTH * 4 / 3) + 2) -struct sdrdata { - /* reverse lookup from sysctl */ - int sysctl; - /* retrieved from SDR, not expected to change */ - u8 stype; - u8 number; - u8 capab; - u16 thresh_mask; - u8 format; - u8 linear; - s16 m; - s16 b; - u8 k; - u8 nominal; - u8 limits[SDR_LIMITS]; - int lim1, lim2; /* index into limits for reported upper and lower limit */ - u8 lim1_write, lim2_write; - u8 string_type; - u8 id_length; - u8 id[SDR_MAX_ID_LENGTH]; - /* retrieved from reading */ - u8 reading; - u8 status; - u8 thresholds; -}; -static struct sdrdata sdrd[MAX_SDR_ENTRIES]; -static int sdrd_count; - - -/* -- SENSORS SYSCTL START -- */ -#define BMC_SYSCTL_IN1 1000 -#define BMC_SYSCTL_TEMP1 1100 -#define BMC_SYSCTL_CURR1 1200 -#define BMC_SYSCTL_FAN1 1300 -#define BMC_SYSCTL_ALARMS 5000 - -/* -- SENSORS SYSCTL END -- */ - -#define MAX_PROC_ENTRIES (MAX_SDR_ENTRIES + 5) -#define MAX_PROCNAME_SIZE 8 -static ctl_table *bmcsensors_dir_table; -static char *bmcsensors_proc_name_pool; - -#define IPMI_SDR_SIZE 67 -#define IPMI_CHUNK_SIZE 16 -static int ipmi_sdr_partial_size = IPMI_CHUNK_SIZE; -static struct ipmi_msg tx_message; /* send message */ -static unsigned char tx_msg_data[IPMI_MAX_MSG_LENGTH + 50]; -static unsigned char rx_msg_data[IPMI_MAX_MSG_LENGTH + 50]; /* sloppy */ -static int rx_msg_data_offset; -static int msgid; /* API to IPMI is long but we'll let i2c-ipmi convert */ -static u16 resid; -static u16 nextrecord; -static int errorcount; - -enum states {STATE_INIT, STATE_RESERVE, STATE_SDR, STATE_SDRPARTIAL, - STATE_READING, STATE_UNCANCEL, STATE_PROCTABLE, STATE_DONE}; -/* YJ : added extra state STATE_PROCTABLE for thread activity */ -static int state; -static int receive_counter; - - -/* IPMI Message defs */ -/* Network Function Codes */ -#define IPMI_NETFN_SENSOR 0x04 -#define IPMI_NETFN_STORAGE 0x0A -/* Commands */ -#define IPMI_RESERVE_SDR 0x22 -#define IPMI_GET_SDR 0x23 -#define IPMI_GET_SENSOR_STATE_READING 0x2D - -/* SDR defs */ -#define STYPE_TEMP 0x01 -#define STYPE_VOLT 0x02 -#define STYPE_CURR 0x03 -#define STYPE_FAN 0x04 - -/* do we really need maximums per-type? */ -#define STYPE_MAX 4 /* the last sensor type we are interested in */ -static u8 bmcs_count[STYPE_MAX + 1]; -static const u8 bmcs_max[STYPE_MAX + 1] = {0, 20, 40, 20, 20}; -/* YJ: on poweredge 1750, we need ^^ */ - -/************************************/ -/* YJ ... */ -static int thread_pid= 0; -static DECLARE_MUTEX_LOCKED(bmc_sem); -/* ... YJ */ -/************************************/ - -/* unpack based on string type, convert to normal, null terminate */ -static void ipmi_sprintf(u8 * to, u8 * from, u8 type, u8 length) -{ - static const u8 *bcdplus = "0123456789 -.:,_"; - int i; - - switch (type) { - case 0: /* unicode */ - for(i = 0; i < length; i++) - *to++ = *from++ & 0x7f; - *to = 0; - break; - case 1: /* BCD Plus */ - for(i = 0; i < length; i++) - *to++ = bcdplus[*from++ & 0x0f]; - *to = 0; - break; - case 2: /* packed ascii */ /* if not a mult. of 3 this will run over */ - for(i = 0; i < length; i += 3) { - *to++ = *from & 0x3f; - *to++ = *from >> 6 | ((*(from+1) & 0xf) << 2); - from++; - *to++ = *from >> 4 | ((*(from+1) & 0x3) << 4); - from++; - *to++ = (*from++ >> 2) & 0x3f; - } - *to = 0; - break; - case 3: /* normal */ - if(length > 1) - memcpy(to, from, length); - to[length] = 0; - break; - } -} - -static const char * threshold_text[] = { - "upper non-recoverable threshold", - "upper critical threshold", - "upper non-critical threshold", - "lower non-recoverable threshold", - "lower critical threshold", - "lower non-critical threshold", - "positive-going hysteresis", - "negative-going hysteresis" /* unused */ -}; - -/* select two out of the 8 possible readable thresholds, and place indexes into the limits - array into lim1 and lim2. Set writable flags */ -static void bmcsensors_select_thresholds(struct sdrdata * sd) -{ - u8 capab = sd->capab; - u16 mask = sd->thresh_mask; - int tmp; - - sd->lim1 = -1; - sd->lim2 = -1; - sd->lim1_write = 0; - sd->lim2_write = 0; - - if(((capab & 0x0c) == 0x04) || /* readable thresholds ? */ - ((capab & 0x0c) == 0x08)) { - /* select upper threshold */ - if(mask & 0x10) { /* upper crit */ - sd->lim1 = 1; - if((capab & 0x0c) == 0x08 && (mask & 0x1000)) - sd->lim1_write = 1; - } - else if(mask & 0x20) { /* upper non-recov */ - sd->lim1 = 0; - if((capab & 0x0c) == 0x08 && (mask & 0x2000)) - sd->lim1_write = 1; - } - else if(mask & 0x08) { /* upper non-crit */ - sd->lim1 = 2; - if((capab & 0x0c) == 0x08 && (mask & 0x0800)) - sd->lim1_write = 1; - } - - /* select lower threshold */ - if((((capab & 0x30) == 0x10) || /* readable ? */ - ((capab & 0x30) == 0x20)) && /* pos hyst */ - sd->stype == STYPE_TEMP) - sd->lim2 = 6; - else if(mask & 0x02) { /* lower crit */ - sd->lim2 = 4; - if((capab & 0x0c) == 0x08 && (mask & 0x0200)) - sd->lim2_write = 1; - } - else if(mask & 0x04) { /* lower non-recov */ - sd->lim2 = 3; - if((capab & 0x0c) == 0x08 && (mask & 0x0400)) - sd->lim2_write = 1; - } - else if(mask & 0x01) { /* lower non-crit */ - sd->lim2 = 5; - if((capab & 0x0c) == 0x08 && (mask & 0x0100)) - sd->lim2_write = 1; - } - } - - /* swap lim1/lim2 if m < 0 or function is 1/x (but not both!) */ - if((sd->m < 0 && sd->linear != 7) || (sd->m >= 0 && sd->linear == 7)) { - tmp = sd->lim1; - sd->lim1 = sd->lim2; - sd->lim2 = tmp; - } - - if(sd->lim1 >= 0) - printk(KERN_INFO "bmcsensors.o: using %s for upper limit\n", - threshold_text[sd->lim1]); -#ifdef DEBUG - else - printk(KERN_INFO "bmcsensors.o: no readable upper limit\n"); -#endif - if(sd->lim2 >= 0) - printk(KERN_INFO "bmcsensors.o: using %s for lower limit\n", - threshold_text[sd->lim2]); -#ifdef DEBUG - else - printk(KERN_INFO "bmcsensors.o: no readable lower limit\n"); -#endif -} - -/* After we have received all the SDR entries and picked out the ones - we are interested in, build a table of the /proc entries and register with i2c. -*/ -static void bmcsensors_build_proc_table() -{ - int i; - int temps = 0, volts = 0, currs = 0, fans = 0; - u8 id[SDR_MAX_UNPACKED_ID_LENGTH]; - - - printk(KERN_INFO "bmcsensors.o: building proc table\n"); - if(!(bmcsensors_dir_table = kmalloc((sdrd_count + 1) * sizeof(struct ctl_table), GFP_KERNEL))) { - printk(KERN_ERR "bmcsensors.o: no memory\n"); - return; /* do more than this */ /* ^^ add 1 or more for alarms, etc. */ - } - if(!(bmcsensors_proc_name_pool = kmalloc((sdrd_count + 0) * MAX_PROCNAME_SIZE, GFP_KERNEL))) { - kfree(bmcsensors_dir_table); - printk(KERN_ERR "bmcsensors.o: no memory\n"); - return; /* do more than this */ /* ^^ add 1 or more for alarms, etc. */ - } - - for(i = 0; i < sdrd_count; i++) { - bmcsensors_dir_table[i].procname = bmcsensors_proc_name_pool + (i * MAX_PROCNAME_SIZE); - bmcsensors_dir_table[i].data = NULL; - bmcsensors_dir_table[i].maxlen = 0; - bmcsensors_dir_table[i].child = NULL; - bmcsensors_dir_table[i].proc_handler = &i2c_proc_real; - bmcsensors_dir_table[i].strategy = &i2c_sysctl_real; - bmcsensors_dir_table[i].de = NULL; - - switch(sdrd[i].stype) { - case(STYPE_TEMP) : - bmcsensors_dir_table[i].ctl_name = BMC_SYSCTL_TEMP1 + temps; - sprintf((char *)bmcsensors_dir_table[i].procname, "temp%d", ++temps); - bmcsensors_dir_table[i].extra1 = &bmcsensors_all; - break; - case(STYPE_VOLT) : - bmcsensors_dir_table[i].ctl_name = BMC_SYSCTL_IN1 + volts; - sprintf((char *)bmcsensors_dir_table[i].procname, "in%d", ++volts); - bmcsensors_dir_table[i].extra1 = &bmcsensors_all; - break; - case(STYPE_CURR) : - bmcsensors_dir_table[i].ctl_name = BMC_SYSCTL_CURR1 + currs; - sprintf((char *)bmcsensors_dir_table[i].procname, "curr%d", ++currs); - bmcsensors_dir_table[i].extra1 = &bmcsensors_all; - break; - case(STYPE_FAN) : - bmcsensors_dir_table[i].ctl_name = BMC_SYSCTL_FAN1 + fans; - sprintf((char *)bmcsensors_dir_table[i].procname, "fan%d", ++fans); - bmcsensors_dir_table[i].extra1 = &bmcsensors_all; - break; - default: /* ?? */ - printk(KERN_INFO "bmcsensors.o: unk stype\n"); - continue; - } - sdrd[i].sysctl = bmcsensors_dir_table[i].ctl_name; - printk(KERN_INFO "bmcsensors.o: registering sensor %d: (type 0x%.2x) " - "(fmt=%d; m=%d; b=%d; k1=%d; k2=%d; cap=0x%.2x; mask=0x%.4x)\n", - i, sdrd[i].stype, sdrd[i].format, - sdrd[i].m, sdrd[i].b,sdrd[i].k & 0xf, sdrd[i].k >> 4, - sdrd[i].capab, sdrd[i].thresh_mask); - if(sdrd[i].id_length > 0) { - ipmi_sprintf(id, sdrd[i].id, sdrd[i].string_type, sdrd[i].id_length); - printk(KERN_INFO "bmcsensors.o: sensors.conf: label %s \"%s\"\n", - bmcsensors_dir_table[i].procname, id); - } - bmcsensors_select_thresholds(sdrd + i); - if(sdrd[i].linear != 0 && sdrd[i].linear != 7) { - printk(KERN_INFO - "bmcsensors.o: sensor %d: nonlinear function 0x%.2x unsupported, expect bad results\n", - i, sdrd[i].linear); - } - if((sdrd[i].format & 0x03) == 0x02) { - printk(KERN_INFO - "bmcsensors.o: sensor %d: 1's complement format unsupported, expect bad results\n", - i); - } else if((sdrd[i].format & 0x03) == 0x03) { - printk(KERN_INFO - "bmcsensors.o: sensor %d: threshold sensor only, no readings available", - i); - } - if(sdrd[i].lim1_write || sdrd[i].lim2_write) - bmcsensors_dir_table[i].mode = 0644; - else - bmcsensors_dir_table[i].mode = 0444; - } - bmcsensors_dir_table[sdrd_count].ctl_name = 0; - - if ((i = i2c_register_entry(&bmc_client, "bmc", - bmcsensors_dir_table, - THIS_MODULE)) < 0) { - printk(KERN_INFO "bmcsensors.o: i2c registration failed.\n"); - kfree(bmcsensors_dir_table); - kfree(bmcsensors_proc_name_pool); - return; - } - bmcsensors_initialized = 3; - bmc_data.sysctl_id = i; - - printk(KERN_INFO "bmcsensors.o: %d reservations cancelled\n", errorcount); - printk(KERN_INFO "bmcsensors.o: registered %d temp, %d volt, %d current, %d fan sensors\n", - temps, volts, currs, fans); -/* - This completes the initialization. The first userspace read - of a /proc value will force the first - bmcsensors_update_client() which starts the - reading of the sensors themselves via IPMI messages. -*/ -} - - -/* Process a sensor reading response */ -static int bmcsensors_rcv_reading_msg(struct ipmi_msg *msg) -{ - if(receive_counter >= sdrd_count) { - /* shouldn't happen */ - receive_counter = 0; - return STATE_DONE; - } - sdrd[receive_counter].reading = msg->data[1]; - sdrd[receive_counter].status = msg->data[2]; - sdrd[receive_counter].thresholds = msg->data[3]; -#ifdef DEBUG - printk(KERN_DEBUG "bmcsensors.o: sensor %d (type %d) reading %d\n", - receive_counter, sdrd[receive_counter].stype, msg->data[1]); -#endif - if(++receive_counter >= sdrd_count) { - receive_counter = 0; - return STATE_DONE; - } - /* don't really need to pass client */ - bmcsensors_get_reading(&bmc_client, receive_counter); - return STATE_READING; -} - -/* Process an SDR response, save the SDR's we like in the sdrd table */ -static int bmcsensors_rcv_sdr_msg(struct ipmi_msg *msg, int state) -{ - u16 record; - int type; - int stype; - int id_length; - int i; - int rstate = STATE_SDR; - int ipmi_ver = 0; - unsigned char * data; - u8 id[SDR_MAX_UNPACKED_ID_LENGTH]; - - - if(msg->data[0] != 0) { - /* cut request in half and try again */ - ipmi_sdr_partial_size /= 2; - if(ipmi_sdr_partial_size < 8) { - printk(KERN_INFO "bmcsensors.o: IPMI buffers too small, giving up\n"); - up (&bmc_sem); /* should wait for thread exit ! */ - return STATE_DONE; - } -#ifdef DEBUG - printk(KERN_INFO "bmcsensors.o: Reducing SDR request size to %d\n", ipmi_sdr_partial_size); -#endif - bmcsensors_get_sdr(0, 0, 0); - return STATE_SDR; - } - if(ipmi_sdr_partial_size < IPMI_SDR_SIZE) { - if(rx_msg_data_offset == 0) { - memcpy(rx_msg_data, msg->data, ipmi_sdr_partial_size + 3); - rx_msg_data_offset = ipmi_sdr_partial_size + 3; - } else { - memcpy(rx_msg_data + rx_msg_data_offset, msg->data + 3, ipmi_sdr_partial_size); - rx_msg_data_offset += ipmi_sdr_partial_size; - } - if(rx_msg_data_offset > rx_msg_data[7] + 7) { - /* got last chunk */ - rx_msg_data_offset = 0; - data = rx_msg_data; - } else { - /* get more */ - record = (rx_msg_data[4] << 8) | rx_msg_data[3]; - bmcsensors_get_sdr(resid, record, rx_msg_data_offset - 3); - return STATE_SDR; - } - } else { - data = msg->data; /* got it in one chunk */ - } - - nextrecord = (data[2] << 8) | data[1]; - /* printk(KERN_INFO "bmcsensors.o: nextrecord %d\n", nextrecord); */ - - - type = data[6]; - if(type == 1 || type == 2) { /* known SDR type */ -/* - version = data[5]; - owner = data[8]; - lun = data[9]; - entity = data[11]; - init = data[13]; -*/ - stype = data[(ipmi_ver == 0x90?16:15)]; - if(stype <= STYPE_MAX) { /* known sensor type */ - if(bmcs_count[stype] >= bmcs_max[stype]) { - if(bmcs_max[stype] > 0) - printk(KERN_INFO - "bmcsensors.o: Limit of %d exceeded for sensor type 0x%x\n", - bmcs_max[stype], stype); -#ifdef DEBUG - else - printk(KERN_INFO - "bmcsensors.o: Ignoring unsupported sensor type 0x%x\n", - stype); -#endif - } else if(sdrd_count >= MAX_SDR_ENTRIES) { - printk(KERN_INFO - "bmcsensors.o: Limit of %d exceeded for total sensors\n", - MAX_SDR_ENTRIES); - nextrecord = 0xffff; - } else if(data[(ipmi_ver == 0x90?17:16)] != 0x01) { - if(type == 1) - ipmi_sprintf(id, &data[51], data[50] >> 6, data[50] & 0x1f); - else - ipmi_sprintf(id, &data[(ipmi_ver == 0x90?30:35)], data[(ipmi_ver == 0x90?29:34)] >> 6, data[(ipmi_ver == 0x90?29:34)] & 0x1f); - printk(KERN_INFO - "bmcsensors.o: skipping non-threshold sensor \"%s\"\n", - id); - } else { - /* add entry to sdrd table */ - sdrd[sdrd_count].stype = stype; - sdrd[sdrd_count].number = data[10]; - sdrd[sdrd_count].capab = data[(ipmi_ver == 0x90?15:14)]; - sdrd[sdrd_count].thresh_mask = (((u16) data[(ipmi_ver == 0x90?21:22)]) << 8) | data[21]; - if(type == 1) { - sdrd[sdrd_count].format = data[(ipmi_ver == 0x90?22:24)] >> 6; - sdrd[sdrd_count].linear = data[(ipmi_ver == 0x90?25:26)] & 0x7f; - sdrd[sdrd_count].m = data[(ipmi_ver == 0x90?26:27)]; - sdrd[sdrd_count].m |= ((u16) (data[(ipmi_ver == 0x90?27:28)] & 0xc0)) << 2; - if(sdrd[sdrd_count].m & 0x0200) - sdrd[sdrd_count].m |= 0xfc00; /* sign extend */ - sdrd[sdrd_count].b = data[(ipmi_ver == 0x90?28:29)]; - sdrd[sdrd_count].b |= ((u16) (data[(ipmi_ver == 0x90?29:30)] & 0xc0)) << 2; - if(sdrd[sdrd_count].b & 0x0200) - sdrd[sdrd_count].b |= 0xfc00; /* sign extend */ - sdrd[sdrd_count].k = data[(ipmi_ver == 0x90?31:32)]; - sdrd[sdrd_count].nominal = data[(ipmi_ver == 0x90?33:34)]; - for(i = 0; i < SDR_LIMITS; i++) /* assume readable */ - sdrd[sdrd_count].limits[i] = data[(ipmi_ver == 0x90?40:39) + i]; - sdrd[sdrd_count].string_type = data[50] >> 6; - id_length = data[50] & 0x1f; - memcpy(sdrd[sdrd_count].id, &data[51], id_length); - sdrd[sdrd_count].id_length = id_length; - } else { - sdrd[sdrd_count].m = 1; - sdrd[sdrd_count].b = 0; - sdrd[sdrd_count].k = 0; - sdrd[sdrd_count].string_type = data[(ipmi_ver == 0x90?29:34)] >> 6; - id_length = data[34] & 0x1f; - if(id_length > 0) - memcpy(sdrd[sdrd_count].id, &data[(ipmi_ver == 0x90?30:35)], id_length); - sdrd[sdrd_count].id_length = id_length; - /* limits?? */ - if(ipmi_ver == 0x90){ - memcpy(sdrd[sdrd_count].id, &data[30], id_length); - sdrd[sdrd_count].id_length = id_length; - } - } - bmcs_count[stype]++; - sdrd_count++; - if (sdrd_count>=MAX_SDR_ENTRIES) nextrecord = 0xffff; /*YJ*/ - - } - } -#ifdef DEBUG - /* peek at the other SDR types */ - } else if(type == 0x10 || type == 0x11 || type == 0x12) { - ipmi_sprintf(id, data + 19, data[18]>>6, data[18] & 0x1f); - if(type == 0x10) { - printk(KERN_INFO "bmcsensors.o: Generic Device acc=0x%x; slv=0x%x; lun=0x%x; type=0x%x; \"%s\"\n", - data[8], data[9], data[10], data[13], id); - } else if(type == 0x11) { - printk(KERN_INFO "bmcsensors.o: FRU Device acc=0x%x; slv=0x%x; log=0x%x; ch=0x%x; type=0x%x; \"%s\"\n", - data[8], data[9], data[10], data[11], data[13], id); - } else { - printk(KERN_INFO "bmcsensors.o: Mgmt Ctllr Device slv=0x%x; \"%s\"\n", - data[8], id); - } - } else if(type == 0x14) { - printk(KERN_INFO "bmcsensors.o: Message Channel Info Records:\n"); - for(i = 0; i < 8; i++) { - printk(KERN_INFO "bmcsensors.o: Channel %d info 0x%x\n", - i, data[9 + i]); - } - } else { - printk(KERN_INFO "bmcsensors.o: Skipping SDR type 0x%x\n", type); -#endif - } - if (nextrecord>=6224) { - nextrecord = 0xffff; /*YJ stop sensor scan on poweredge 1750 */ - } - if (ipmi_ver != 0x90) { - if (nextrecord>=6224) { - nextrecord = 0xffff; /*YJ stop sensor scan on poweredge 1750 */ - } - } - - if(nextrecord == 0xFFFF) { - if(sdrd_count == 0) { - printk(KERN_INFO "bmcsensors.o: No recognized sensors found.\n"); - /* unregister?? */ - rstate = STATE_DONE; - up (&bmc_sem); /* should wait for thread exit !!! */ - } else { - /* YJ ...*/ - printk(KERN_INFO "bmcsensors.o: all sensors detected\n"); - rstate = STATE_PROCTABLE; - /* YJ bmcsensors_build_proc_table() call by thread */ - /* ... YJ */ - } - - } else { - - bmcsensors_get_sdr(0, nextrecord, 0); - } - return rstate; -} - -/* Process incoming messages based on internal state */ -static void bmcsensors_rcv_msg(struct ipmi_msg *msg) -{ - - switch(state) { - case STATE_INIT: - case STATE_RESERVE: - resid = (((u16)msg->data[2]) << 8) | msg->data[1]; -#ifdef DEBUG - printk(KERN_DEBUG "bmcsensors.o: Got first resid 0x%.4x\n", resid); -#endif - bmcsensors_get_sdr(0, 0, 0); - state = STATE_SDR; - break; - - case STATE_SDR: - case STATE_SDRPARTIAL: - state = bmcsensors_rcv_sdr_msg(msg, state); - /*YJ ...*/ - if (state==STATE_PROCTABLE){ - -#ifdef DEBUG - printk(KERN_DEBUG "releasing thread\n"); -#endif - - up (&bmc_sem); - } - /*YJ bmcsensors_build_proc_table() called by thread */ - /* ... YJ */ - break; - - case STATE_READING: - state = bmcsensors_rcv_reading_msg(msg); - break; - - case STATE_UNCANCEL: - resid = (((u16)msg->data[2]) << 8) | msg->data[1]; -#ifdef DEBUG - printk(KERN_DEBUG "bmcsensors.o: Got new resid 0x%.4x\n", resid); -#endif - rx_msg_data_offset = 0; - bmcsensors_get_sdr(0, nextrecord, 0); - state = STATE_SDR; - break; - - case STATE_DONE: - case STATE_PROCTABLE: - break; - - default: - state = STATE_INIT; - } -} - - -/* Incoming message handler */ -static void bmcsensors_msg_handler(struct ipmi_recv_msg *msg, - void * handler_data) -{ - if(state == STATE_SDR && msg->msg.data[0] == 0xc5) { - /* )(*&@(*&#@$ reservation cancelled, get new resid */ - if(++errorcount > 275) { - printk(KERN_ERR - "bmcsensors.o: Too many reservations cancelled, giving up\n"); - state = STATE_DONE; - up (&bmc_sem); /* YJ : should make sure thread exited ! */ - } else { -#ifdef DEBUG - printk(KERN_DEBUG - "bmcsensors.o: resid 0x%04x cancelled, getting new one\n", resid); -#endif - bmcsensors_reserve_sdr(); - state = STATE_UNCANCEL; - } - } else if (msg->msg.data[0] != 0 && msg->msg.data[0] != 0xca && - msg->msg.data[0] != 0xce) { - /* YJ : accept 0xce */ - printk(KERN_ERR - "bmcsensors.o: Error 0x%x on cmd 0x%x/0x%x; state = %d; probably fatal.\n", - msg->msg.data[0], msg->msg.netfn & 0xfe, msg->msg.cmd, state); - } else { - bmcsensors_rcv_msg(&(msg->msg)); - } - ipmi_free_recv_msg(msg); -} - -/* callback from i2c-ipmi */ -static int bmcsensors_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - bmcsensors_msg_handler((struct ipmi_recv_msg *) arg, NULL); - return 0; -} - -/************** Message Sending **************/ - -/* Send an IPMI message */ -static void bmcsensors_send_message(struct ipmi_msg * msg) -{ -#ifdef DEBUG - printk(KERN_INFO "bmcsensors.o: Send BMC msg, cmd: 0x%x\n", - msg->cmd); -#endif - bmc_client.adapter->algo->slave_send((struct i2c_adapter *) &bmc_client, - (char *) msg, msgid++); - -} - -/* Compose and send a "reserve SDR" message */ -static void bmcsensors_reserve_sdr(void) -{ - tx_message.netfn = IPMI_NETFN_STORAGE; - tx_message.cmd = IPMI_RESERVE_SDR; - tx_message.data_len = 0; - tx_message.data = NULL; - printk(KERN_INFO "bmcsensors.o: reserve_sdr...\n"); - bmcsensors_send_message(&tx_message); -} - -/* Componse and send a "get SDR" message */ -static void bmcsensors_get_sdr(u16 res_id, u16 record, u8 offset) -{ -#ifdef DEBUG - printk(KERN_DEBUG "bmcsensors.o: Get SDR 0x%x 0x%x 0x%x\n", - res_id, record, offset); -#endif - tx_message.netfn = IPMI_NETFN_STORAGE; - tx_message.cmd = IPMI_GET_SDR; - tx_message.data_len = 6; - tx_message.data = tx_msg_data; - tx_msg_data[0] = res_id & 0xff; - tx_msg_data[1] = res_id >> 8; - tx_msg_data[2] = record & 0xff; - tx_msg_data[3] = record >> 8; - tx_msg_data[4] = offset; - tx_msg_data[5] = ipmi_sdr_partial_size; - bmcsensors_send_message(&tx_message); -} - -/* Compose and send a "get sensor reading" message */ -static void bmcsensors_get_reading(struct i2c_client *client, int i) -{ - tx_message.netfn = IPMI_NETFN_SENSOR; - tx_message.cmd = IPMI_GET_SENSOR_STATE_READING; - tx_message.data_len = 1; - tx_message.data = tx_msg_data; - tx_msg_data[0] = sdrd[i].number; - bmcsensors_send_message(&tx_message); -} - -/**************** Initialization ****************/ - -static int bmcsensors_attach_adapter(struct i2c_adapter *adapter) -{ - printk(KERN_INFO "bmcsensors.o: attach_adapter...\n"); - - if(adapter->algo->id != I2C_ALGO_IPMI){ - printk(KERN_INFO "bmcsensors.o: attach_adapter, expected 0x%x, got 0x%x\n", I2C_ALGO_IPMI, adapter->algo->id); - return 0; - } - - if(bmcsensors_initialized >= 2) { - printk(KERN_INFO "bmcsensors.o: Additional IPMI adapter not supported\n"); - return 0; - } - - return bmcsensors_detect(adapter, 0, 0, 0); -} - -static int bmcsensors_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int err, i; - - bmc_client.id = 0; - bmc_client.adapter = adapter; - bmc_data.valid = 0; - - if ((err = i2c_attach_client(&bmc_client))) { - printk(KERN_ERR "attach client error in bmcsensors_detect()\n"); - return err; - } - bmcsensors_initialized = 2; - - state = STATE_INIT; - sdrd_count = 0; - receive_counter = 0; - rx_msg_data_offset = 0; - errorcount = 0; - ipmi_sdr_partial_size = IPMI_CHUNK_SIZE; - for(i = 0; i <= STYPE_MAX; i++) - bmcs_count[i] = 0; - - /* send our first message, which kicks things off */ - printk(KERN_INFO "bmcsensors.o: Registered client, scanning for sensors...\n"); - bmcsensors_reserve_sdr(); - /* don't call i2c_register_entry until we scan the SDR's */ - return 0; -} - -static int bmcsensors_detach_client(struct i2c_client *client) -{ - int err; - - if(bmcsensors_initialized >= 3) { - kfree(bmcsensors_dir_table); - kfree(bmcsensors_proc_name_pool); - i2c_deregister_entry(((struct bmcsensors_data *) (client->data))-> - sysctl_id); - } - - if ((err = i2c_detach_client(client))) { -/* - printk - ("bmcsensors.o: Client deregistration failed, client not detached.\n"); -*/ - return err; - } - - bmcsensors_initialized = 1; - return 0; -} - - -static void bmc_do_pause(unsigned int amount) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(amount); -} - -static void bmcsensors_update_client(struct i2c_client *client) -{ - struct bmcsensors_data *data = client->data; - int j = 0; - -/* - down(&data->update_lock); -*/ - - /* if within 3 seconds you get old data */ - if ((jiffies - data->last_updated > 3 * HZ) || - (jiffies < data->last_updated) || !data->valid) { - /* don't start an update cycle if one already in progress */ - if(state != STATE_READING) { - state = STATE_READING; -#ifdef DEBUG - printk(KERN_DEBUG "bmcsensors.o: starting update\n"); -#endif - bmcsensors_get_reading(client, 0); - } - /* wait 4 seconds max */ - while(state == STATE_READING && j++ < 100) - bmc_do_pause(HZ / 25); -#ifdef DEBUG - printk(KERN_DEBUG "bmcsensors.o: update complete; j = %d\n", j); -#endif - data->last_updated = jiffies; - data->valid = 1; - } - -/* - up(&data->update_lock); -*/ -} - - -/************* /proc callback helper functions *********/ - -/* need better way to map from sysctl to sdrd record number */ -static struct sdrdata * find_sdrd(int sysctl) -{ - int i; - - for(i = 0; i < sdrd_count; i++) - if(sdrd[i].sysctl == sysctl) - return sdrd + i; - return NULL; -} - -/* IPMI V1.5 Section 30 */ -static const int exps[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000}; - -/* Return 0 for fan, 2 for temp, 3 for voltage - We could make it variable based on the accuracy (= log10(m * 10**k2)); - this would work for /proc output, however libsensors resolution - is statically set in lib/chips.c */ -static int decplaces(struct sdrdata *sd) -{ - switch(sd->stype) { - case STYPE_TEMP: - return 2; - case STYPE_CURR: - case STYPE_VOLT: - return 3; - case STYPE_FAN: - default: - return 0; - } -} - -/* convert a raw value to a reading. IMPI V1.5 Section 30 */ -/* 1/x is the only "linearization function" supported */ -static long conv_val(int value, struct sdrdata *sd) -{ - u8 k1, k2; - long r; - - r = value * sd->m; - k1 = sd->k & 0x0f; - k2 = sd->k >> 4; - if(k1 < 8) - r += sd->b * exps[k1]; - else - r += sd->b / exps[16 - k1]; - r *= exps[decplaces(sd)]; - if(k2 < 8) { - if(sd->linear != 7) - r *= exps[k2]; - else - // this will always truncate to 0: r = 1 / (exps[k2] * r); - r = 0; - } else { - if(sd->linear != 7) - r /= exps[16 - k2]; - else { - if(r != 0) - // 1 / x * 10 ** (-m) == 10 ** m / x - r = exps[16 - k2] / r; - else - r = 0; - } - } - return r; -} - - -/************** /proc callbacks *****************/ - -static void bmcsensors_all(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct sdrdata *sd; -/* - struct bmcsensors_data *data = client->data; -*/ - - if((sd = find_sdrd(ctl_name)) == NULL) { - *nrels_mag = 0; - return; - } - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = decplaces(sd); - else if (operation == SENSORS_PROC_REAL_READ) { - bmcsensors_update_client(client); - if(sd->lim2 >= 0) { - if(sd->stype == STYPE_TEMP) /* upper limit first */ - results[0] = - conv_val(sd->limits[sd->lim1], sd); - else /* lower limit first */ - results[0] = - conv_val(sd->limits[sd->lim2], sd); - } else - results[0] = 0; - if(sd->stype == STYPE_FAN) { /* lower limit only */ - results[1] = conv_val(sd->reading, sd); - *nrels_mag = 2; - } else { - if(sd->lim1 >= 0) { - if(sd->stype == STYPE_TEMP) { /* lower 2nd */ - results[1] = - conv_val(sd->limits[sd->lim2], sd); - if(sd->lim2 == 6) /* pos. thresh. */ - results[1] = results[0] - - results[1]; - } else /* upper 2nd */ - results[1] = - conv_val(sd->limits[sd->lim1], sd); - } else - results[1] = 0; - results[2] = conv_val(sd->reading, sd); - *nrels_mag = 3; - } - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - /* unimplemented */ - } - } -} - -#if 0 -static void bmcsensors_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct bmcsensors_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - bmcsensors_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} -#endif - -/* YJ ... */ -static int bmc_thread(void *dummy){ - - lock_kernel(); - daemonize(); - unlock_kernel(); - - strcpy(current->comm, "bmc-sensors"); - - if(down_interruptible(&bmc_sem)) { - - printk("exiting..."); - - thread_pid= 0; - up (&bmc_sem); - - return 0; - } - - if (state == STATE_PROCTABLE){ - - bmcsensors_build_proc_table(); - - state = STATE_DONE; - - printk(KERN_INFO "bmcsensors.o: bmcsensor thread done\n" ); - - } - - thread_pid= 0; - - up (&bmc_sem); - - return 0; -} -/* ... YJ */ - -static int __init sm_bmcsensors_init(void) -{ - printk(KERN_INFO "bmcsensors.o version %s (%s)\n", LM_VERSION, LM_DATE); - /* YJ ... */ - init_MUTEX_LOCKED(&bmc_sem); - - thread_pid= kernel_thread(bmc_thread, NULL, 0); - - if (thread_pid<0){ - printk(KERN_ERR "bmcsensors.o : Could not initialize bmc thread. Aborting\n"); - return 0; - } - /* ... YJ */ - - return i2c_add_driver(&bmcsensors_driver); -} - -static void __exit sm_bmcsensors_exit(void) -{ - int j; - j= 0; - /* YJ ... */ - printk(KERN_INFO "bmcsensors.o sleeping a while\n"); - while( (j++ < 50)){ - bmc_do_pause(HZ / 25); - } - if (thread_pid > 0){ - printk(KERN_INFO "bmcsensors.o stopping kernel thread\n"); - state= STATE_DONE; - j= 0; - up (&bmc_sem); - printk(KERN_INFO "bmcsensors.o waiting...\n"); - /* make sure kernel thread does not access driver memory any more */ - while((thread_pid > 0)&& (j++ < 100)){ - bmc_do_pause(HZ / 25); - } - printk(KERN_INFO "bmcsensors.o OK\n"); - } - j= 0; - /* sleep for debug... not necessary ? */ - printk(KERN_INFO "bmcsensors.o sleeping again\n"); - while( (j++ < 50)){ - bmc_do_pause(HZ / 25); - } - /* ...YJ */ - printk(KERN_INFO "bmcsensors.o i2c cleanup\n"); - i2c_del_driver(&bmcsensors_driver); -} - - - -MODULE_AUTHOR("Mark D. Studebaker "); -MODULE_DESCRIPTION("IPMI BMC sensors"); -MODULE_LICENSE("GPL"); - -module_init(sm_bmcsensors_init); -module_exit(sm_bmcsensors_exit); diff --git a/kernel/chips/bt869.c b/kernel/chips/bt869.c deleted file mode 100644 index aceea8d0..00000000 --- a/kernel/chips/bt869.c +++ /dev/null @@ -1,886 +0,0 @@ -/* - bt869.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - - Copyright (c) 1998, 1999 Frodo Looijaard - Copyright (c) 2001, 2002 Stephen Davies - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - - -#define DEBUG 1 - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; - -/* found only at 0x44 or 0x45 */ -static unsigned short normal_i2c_range[] = { 0x44, 0x45, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(bt869); - -/* Many bt869 constants specified below */ - -/* The bt869 registers */ -/* Coming soon: Many, many registers */ - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - - /*none */ - -/* Initial values */ -/*none*/ - -/* Each client has this additional data */ -struct bt869_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 status[3]; /* Register values */ - u16 res[2]; /* Resolution XxY */ - u8 ntsc; /* 1=NTSC, 0=PAL */ - u8 half; /* go half res */ - u8 depth; /* screen depth */ - u8 colorbars; /* turn on/off colorbar calibration screen */ - u8 svideo; /* output format: (2=RGB) 1=SVIDEO, 0=Composite */ -}; - -static int bt869_attach_adapter(struct i2c_adapter *adapter); -static int bt869_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void bt869_init_client(struct i2c_client *client); -static int bt869_detach_client(struct i2c_client *client); -static int bt869_read_value(struct i2c_client *client, u8 reg); -static int bt869_write_value(struct i2c_client *client, u8 reg, u16 value); -static void bt869_write_values(struct i2c_client *client, u16 *values); -static void bt869_status(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void bt869_ntsc(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void bt869_res(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void bt869_half(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void bt869_colorbars(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void bt869_svideo(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void bt869_depth(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void bt869_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver bt869_driver = { - .name = "BT869 video-output chip driver", - .id = I2C_DRIVERID_BT869, - .flags = I2C_DF_NOTIFY, - .attach_adapter = bt869_attach_adapter, - .detach_client = bt869_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define BT869_SYSCTL_STATUS 1000 -#define BT869_SYSCTL_NTSC 1001 -#define BT869_SYSCTL_HALF 1002 -#define BT869_SYSCTL_RES 1003 -#define BT869_SYSCTL_COLORBARS 1004 -#define BT869_SYSCTL_DEPTH 1005 -#define BT869_SYSCTL_SVIDEO 1006 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected bt869. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table bt869_dir_table_template[] = { - {BT869_SYSCTL_STATUS, "status", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &bt869_status}, - {BT869_SYSCTL_NTSC, "ntsc", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &bt869_ntsc}, - {BT869_SYSCTL_RES, "res", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &bt869_res}, - {BT869_SYSCTL_HALF, "half", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &bt869_half}, - {BT869_SYSCTL_COLORBARS, "colorbars", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &bt869_colorbars}, - {BT869_SYSCTL_DEPTH, "depth", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &bt869_depth}, - {BT869_SYSCTL_SVIDEO, "svideo", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &bt869_svideo}, - {0} -}; - -/* ****************** - -720x576, 27.5MHz, PAL, no overscan compensation. - -This mode should be use for digital video, DVD playback etc. - -NOTE: This mode for PAL, see 720x480 for an equivalent NTSC mode -NOTE: -- Steve Davies - - -Compatible X modeline: - - Mode "720x576-BT869" - DotClock 27.5 - HTimings 720 744 800 880 - VTimings 576 581 583 625 - EndMode - - -625LINE=1 625 line output format -BST_AMP[7:0]=x57 87 Burst ampl. multiplication factor (PAL std??) -BY_PLL=0 Use the PLL -CATTENUATE[2:0]=0 No chroma attenuation -CCF1B1[7:0]=0 close caption stuff -CCF1B2[7:0]=0 close caption stuff -CCF2B1[7:0]=0 close caption stuff -CCF2B2[7:0]=0 close caption stuff -CCORING[2:0]=0 Bypass chroma coring -CCR_START[8:0]=0 [CCR_START[8]=0; CCR_START[7:0]=0] Close-caption clock runin start from hsync -CC_ADD[11:0]=xD2 210 [CC_ADD[11:8]=0; CC_ADD[7:0]=xD2] Close-caption DTO increment -CHECK_STAT=0 Don't check monitor status -CLPF[1:0]=0 Hoz chroma lowpass filter=Bypass -DACDISA=1 Disable DACA -DACDISB=0 Don't disable DACB -DACDISC=0 Don't disable DACC -DACOFF=0 Don't disable the DACs -DATDLY = 0 normal -DATSWP=0 normal -DCHROMA=0 Don't blank chroma -DIS_FFILT=1 Disable flickerfilter -DIS_GMSHC=1 Disable chroma psuedo-gamma removal -DIS_GMSHY=1 Disable luma pseudo gamma removal -DIS_GMUSHC=1 Disable chroma anti-pseudo gamma removal -DIS_GMUSHY=1 Disable luma anti-pseudo gamma removal -DIS_SCRESET=0 Normal subcarrier phase resets -DIS_YFLPF=0 Disable Luma initial hoz low pass filter -DIV2=0 Input pixel rate not divided by 2 -ECBAR=0 No colour bars -ECCF1=0 Disable closed caption -ECCF2=0 Disable closed caption -ECCGATE=0 Normal close caption encoding -ECLIP=0 0=disable clipping -EN_ASYNC=0 set to 0 for normal operation -EN_BLANKO=0 BLANK is an input -EN_DOT=0 Disables dot clock sync on BLANK pin -EN_OUT=1 Allows outputs to be enabled -EN_XCLK=1 Use CLKI pin as clock source -ESTATUS[1:0]=0 Used to select readback register -FIELDI=0 Logical 1 on FIELD indicates even field -F_SELC[2:0]=0 5 line chroma flickerfilter -F_SELY[2:0]=0 5 line luma flickerfilter -HBURST_BEGIN[7:0]=x98 152 Chroma burst start point in clocks -HBURST_END[7:0]=x58 88 Chroma burst end point in clocks - 128 -HSYNCI=0 Active low HSYNC -HSYNC_WIDTH[7:0]=x80 128 Analogue sync width in clocks -HSYNOFFSET[9:0]=0 [HSYNOFFSET[9:8]=0; HSYNOFFSET[7:0]=0] hsync in "standard position" -HSYNWIDTH[5:0]=2 2 pixel hsync width -H_ACTIVE[9:0]=x2D0 720 [H_ACTIVE[9:8]=2; H_ACTIVE[7:0]=xD0] Active pixels per line -H_BLANKI[8:0]=x84 132 [H_BLANKI[8]=0; H_BLANKI[7:0]=x84] End of blanking of input video -H_BLANKO[9:0]=x120 288 [H_BLANKO[9:8]=1; H_BLANKO[7:0]=x20] End of blanking from hoz sync leading edge -H_CLKI[10:0]=x378 888 [H_CLKI[10:8]=3; H_CLKI[7:0]=x78] Input line length total in clocks -H_CLKO[11:0]=x6e0 1760 [H_CLKO[11:8]=6; H_CLKO[7:0]=xe0] Output clocks per line -H_FRACT[7:0]=0 0 fractional input clocks per line -IN_MODE[2:0]=0 24Bit RGB muxed -LUMADLY[1:0]=0 0 pixel delay on Y_DLY luma -MCB[7:0]=x49 73 Mult factor for CB prior to subcarrier mod. -MCR[7:0]=x82 130 Mult factor for CR prior to subcarrier mod. -MODE2X=0 Don't divide clock input by 2 -MSC[31:0]=x2945E0B4 692445365 [MSC[31:24]=x29; MSC[23:16]=x45; MSC[15:8]=xE0; MSC[7:0]=xB4] Subcarrier incr. -MY[7:0]=x8C 140 Mult factor for Y -NI_OUT=0 Normal interlaced output -OUT_MODE[1:0]=0 video0-3 is CVBS, Y, C, Y_DLY -OUT_MUXA[1:0]=0 Don't care as DACA is disabled -OUT_MUXB[1:0]=1 Output video[1] (Y) on DACB -OUT_MUXC[1:0]=2 Output video[2] (C) on DACC -PAL_MD=1 Video output in PAL mode -PHASE_OFF[7:0]=0 Subcarrier phase offset -PLL_FRACT[15:0]=x30 48 [PLL_FRACT[15:8]=0x0; PLL_FRACT[7:0]=x30] frac portion of pll multiplier -PLL_INT[5:0]=0x0C 12 Int portion of pll multiplier -SETUP=0 7.5-IRE setup disabled -SLAVER=1 -SRESET=0 Don't do a software reset -SYNC_AMP[7:0]=xF0 240 Sync amp mult. factor (PAL std???) -VBLANKDLY=0 Extra line of blanking in 2nd field? -VSYNCI=0 Active low VSYNC -VSYNC_DUR=0 2.5line VSYNC duration on output -VSYNCOFFSET[10:0]=0 [VSYNOFFSET[10:8]=0; VSYNOFFSET[7:0]=0] VSYNC in standard position -VSYNWIDTH[2:0]=1 1 line of vsync width -V_ACTIVEI[9:0]=x240 576 [V_ACTIVEI[9:0]=2; V_ACTIVEI[7:0]=x40] Active input lines -V_ACTIVEO[8:0]=x122 290 [V_ACTIVE0[8]=1; V_ACTIVEO[7:0]=x22] -V_BLANKI[7:0]=x2A 42 Input lines from vsync to first active line -V_BLANKO[7:0]=x16 22 -V_LINESI[9:0]=x271 625 [V_LINESI[9:8]=2; V_LINESI[7:0]=x71] Number of input lines -V_SCALE[13:0]=x1000 4096 [V_SCALE[13:8]=x10; V_SCALE[7:0]=0] Vert scale coefficient="none"? -YATTENUATE[2:0]=0 no luma attenuation -YCORING[2:0]=0 Luma-coring bypass -YLPF[1:0]=0 Luma hoz low pass filter=bypass - -***************** */ - -static u16 registers_720_576[] = - { - 0x6e, 0x00, /* HSYNOFFSET[7:0]=0 */ - 0x70, 0x02, /* HSYNOFFSET[9:8]=0; HSYNWIDTH[5:0]=2 */ - 0x72, 0x00, /* VSYNOFFSET[7:0]=0 */ - 0x74, 0x01, /* DATDLY = 0; DATSWP=0; VSYNOFFSET[10:8]=0; VSYNWIDTH[2:0]=1 */ - 0x76, 0xe0, /* H_CLKO[7:0]=xe0 */ - 0x78, 0xd0, /* H_ACTIVE[7:0]=xD0 */ - 0x7a, 0x80, /* HSYNC_WIDTH[7:0]=x80 */ - 0x7c, 0x98, /* HBURST_BEGIN[7:0]=x98 */ - 0x7e, 0x58, /* HBURST_END[7:0]=x58 */ - 0x80, 0x20, /* H_BLANKO[7:0]=x20 */ - 0x82, 0x16, /* V_BLANKO[7:0]=x16 */ - 0x84, 0x22, /* V_ACTIVEO[7:0]=x22 */ - 0x86, 0xa6, /* V_ACTIVE0[8]=1; H_ACTIVE[9:8]=2; H_CLKO[11:8]=6 */ - 0x88, 0x00, /* H_FRACT[7:0]=0 */ - 0x8a, 0x78, /* H_CLKI[7:0]=x78 */ - 0x8c, 0x80, /* H_BLANKI[7:0]=x84 */ - 0x8e, 0x03, /* VBLANKDLY=0; H_BLANKI[8]=0; H_CLKI[10:8]=3 */ - 0x90, 0x71, /* V_LINESI[7:0]=x71 */ - 0x92, 0x2a, /* V_BLANKI[7:0]=x2A */ - 0x94, 0x40, /* V_ACTIVEI[7:0]=x40 */ - 0x96, 0x0a, /* CLPF[1:0]=0; YLPF[1:0]=0; V_ACTIVEI[9:0]=2; V_LINESI[9:8]=2 */ - 0x98, 0x00, /* V_SCALE[7:0]=0 */ - 0x9a, 0x50, /* H_BLANKO[9:8]=1; V_SCALE[13:8]=x10 */ - 0x9c, 0x30, /* PLL_FRACT[7:0]=x30 */ - 0x9e, 0x0, /* PLL_FRACT[15:8]=0x0 */ - 0xa0, 0x8c, /* EN_XCLK=1; BY_PLL=0; PLL_INT[5:0]=0x0C */ - 0xa2, 0x24, /* ECLIP=0; PAL_MD=1; DIS_SCRESET=0; VSYNC_DUR=0; 625LINE=1; SETUP=0; NI_OUT=0 */ - 0xa4, 0xf0, /* SYNC_AMP[7:0]=xF0 */ - 0xa6, 0x57, /* BST_AMP[7:0]=x57 */ - 0xa8, 0x82, /* MCR[7:0]=x82 */ - 0xaa, 0x49, /* MCB[7:0]=x49 */ - 0xac, 0x8c, /* MY[7:0]=x8C */ - 0xae, 0xb4, /* MSC[7:0]=xb4 */ - 0xb0, 0xe0, /* MSC[15:8]=xe0 */ - 0xb2, 0x45, /* MSC[23:16]=x45 */ - 0xb4, 0x29, /* MSC[31:24]=x29 */ - 0xb6, 0x00, /* PHASE_OFF[7:0]=0 */ - //0xba, 0x21, /* SRESET=0; CHECK_STAT=0; SLAVER=1; DACOFF=0; DACDISC=0; DACDISB=0; DACDISA=1 */ - 0xc4, 0x01, /* ESTATUS[1:0]=0; ECCF2=0; ECCF1=0; ECCGATE=0; ECBAR=0; DCHROMA=0; EN_OUT=1 */ - 0xc6, 0x00, /* EN_BLANKO=0; EN_DOT=0; FIELDI=0; VSYNCI=0; HSYNCI=0; IN_MODE[2:0]=0(24bRGB) */ - 0xc8, 0x40, /* DIS_YFLPF=0; DIS_FFILT=1; F_SELC[2:0]=0; F_SELY[2:0]=0 */ - 0xca, 0xc0, /* DIS_GMUSHY=1; DIS_GMSHY=1; YCORING[2:0]=0; YATTENUATE[2:0]=0 */ - 0xcc, 0xc0, /* DIS_GMUSHC=1; DIS_GMSHC=1; CCORING[2:0]=0; CATTENUATE[2:0]=0 */ - //0xce, 0x24, /* OUT_MUXC=2 [C]; OUT_MUXB=1 [Y]; OUT_MUXA=0 [CVBS, but disabled]*/ - //0xce, 0x04, /* OUT_MUXC=0 [CVBS]; OUT_MUXB=1 [Y]; OUT_MUXA=0 [CVBS, but disabled]*/ - 0xd6, 0x00, /* OUT_MODE[1:0]=0; LUMADLY[1:0]=0 */ - 0, 0 - }; - - -/* ****************** - -720x480, 27.5MHz, NTSC no overscan compensation. - -This mode should be use for digital video, DVD playback etc. - -NOTE: This mode for NTSC, see 720x576 for an equivalent PAL mode -NOTE: -- Steve Davies - -Compatible X modeline: - - Mode "720x480-BT869" - DotClock 27.5 - HTimings 720 744 800 872 - VTimings 480 483 485 525 - EndMode - - -625LINE=0 not 625 line output format -BST_AMP[7:0]=x74 116 Burst ampl. multiplication factor (NTSC std??) -BY_PLL=0 Use the PLL -CATTENUATE[2:0]=0 No chroma attenuation -CCF1B1[7:0]=0 close caption stuff -CCF1B2[7:0]=0 close caption stuff -CCF2B1[7:0]=0 close caption stuff -CCF2B2[7:0]=0 close caption stuff -CCORING[2:0]=0 Bypass chroma coring -CCR_START[8:0]=0 [CCR_START[8]=0; CCR_START[7:0]=0] Close-caption clock runin start from hsync -CC_ADD[11:0]=xD2 210 [CC_ADD[11:8]=0; CC_ADD[7:0]=xD2] Close-caption DTO increment -CHECK_STAT=0 Don't check monitor status -CLPF[1:0]=0 Hoz chroma lowpass filter=Bypass -DACDISA=1 Disable DACA -DACDISB=0 Don't disable DACB -DACDISC=0 Don't disable DACC -DACOFF=0 Don't disable the DACs -DATDLY = 0 normal -DATSWP=0 normal -DCHROMA=0 Don't blank chroma -DIS_FFILT=1 Disable flickerfilter -DIS_GMSHC=1 Disable chroma psuedo-gamma removal -DIS_GMSHY=1 Disable luma pseudo gamma removal -DIS_GMUSHC=1 Disable chroma anti-pseudo gamma removal -DIS_GMUSHY=1 Disable luma anti-pseudo gamma removal -DIS_SCRESET=0 Normal subcarrier phase resets -DIS_YFLPF=0 Disable Luma initial hoz low pass filter -DIV2=0 Input pixel rate not divided by 2 -ECBAR=0 No colour bars -ECCF1=0 Disable closed caption -ECCF2=0 Disable closed caption -ECCGATE=0 Normal close caption encoding -ECLIP=0 0=disable clipping -EN_ASYNC=0 set to 0 for normal operation -EN_BLANKO=0 BLANK is an input -EN_DOT=0 Disables dot clock sync on BLANK pin -EN_OUT=1 Allows outputs to be enabled -EN_XCLK=1 Use CLKI pin as clock source -ESTATUS[1:0]=0 Used to select readback register -FIELDI=0 Logical 1 on FIELD indicates even field -F_SELC[2:0]=0 5 line chroma flickerfilter -F_SELY[2:0]=0 5 line luma flickerfilter -HBURST_BEGIN[7:0]=x92 146 Chroma burst start point in clocks -HBURST_END[7:0]=x57 87 Chroma burst end point in clocks - 128 -HSYNCI=0 Active low HSYNC -HSYNC_WIDTH[7:0]=x80 128 Analogue sync width in clocks -HSYNOFFSET[9:0]=0 [HSYNOFFSET[9:8]=0; HSYNOFFSET[7:0]=0] hsync in "standard position" -HSYNWIDTH[5:0]=2 2 pixel hsync width -H_ACTIVE[9:0]=x2D0 720 [H_ACTIVE[9:8]=2; H_ACTIVE[7:0]=xD0] Active pixels per line -H_BLANKI[8:0]=x80 128 [H_BLANKI[8]=0; H_BLANKI[7:0]=x80] End of blanking of input video -H_BLANKO[9:0]=x102 258 [H_BLANKO[9:8]=1; H_BLANKO[7:0]=x2] End of blanking from hoz sync leading edge -H_CLKI[10:0]=x368 872 [H_CLKI[10:8]=3; H_CLKI[7:0]=x68] Input line length total in clocks -H_CLKO[11:0]=x6d0 1744 [H_CLKO[11:8]=6; H_CLKO[7:0]=xD0] Output clocks per line -H_FRACT[7:0]=0 0 fractional input clocks per line -IN_MODE[2:0]=0 24Bit RGB muxed -LUMADLY[1:0]=0 0 pixel delay on Y_DLY luma -MCB[7:0]=x43 67 Mult factor for CB prior to subcarrier mod. -MCR[7:0]=x77 119 Mult factor for CR prior to subcarrier mod. -MODE2X=0 Don't divide clock input by 2 -MSC[31:0]=x215282E5 559055589 [MSC[31:24]=x21; MSC[23:16]=x52; MSC[15:8]=x82; MSC[7:0]=xE5] Subcarrier incr. -MY[7:0]=x85 133 Mult factor for Y -NI_OUT=0 Normal interlaced output -OUT_MODE[1:0]=0 video0-3 is CVBS, Y, C, Y_DLY -OUT_MUXA[1:0]=0 Don't care as DACA is disabled -OUT_MUXB[1:0]=1 Output video[1] (Y) on DACB -OUT_MUXC[1:0]=2 Output video[2] (C) on DACC -PAL_MD=0 Video output in PAL mode? No. -PHASE_OFF[7:0]=0 Subcarrier phase offset -PLL_FRACT[15:0]=x30 48 [PLL_FRACT[15:8]=0x0; PLL_FRACT[7:0]=x30] frac portion of pll multiplier -PLL_INT[5:0]=0x0C 12 Int portion of pll multiplier -SETUP=1 7.5-IRE enabled for NTSC -SLAVER=1 -SRESET=0 Don't do a software reset -SYNC_AMP[7:0]=xE5 229 Sync amp mult. factor (PAL std???) -VBLANKDLY=0 Extra line of blanking in 2nd field? -VSYNCI=0 Active low VSYNC -VSYNC_DUR=1 2.5line VSYNC duration on output (Yes for NTSC) -VSYNCOFFSET[10:0]=0 [VSYNOFFSET[10:8]=0; VSYNOFFSET[7:0]=0] VSYNC in standard position -VSYNWIDTH[2:0]=1 1 line of vsync width -V_ACTIVEI[9:0]=x1E0 480 [V_ACTIVEI[9:0]=1; V_ACTIVEI[7:0]=xE0] Active input lines -V_ACTIVEO[8:0]=xF0 240 [V_ACTIVE0[8]=0; V_ACTIVEO[7:0]=xF0] -V_BLANKI[7:0]=x2A 42 Input lines from vsync to first active line -V_BLANKO[7:0]=x16 22 -V_LINESI[9:0]=x20D 525 [V_LINESI[9:8]=2; V_LINESI[7:0]=x0D] Number of input lines -V_SCALE[13:0]=x1000 4096 [V_SCALE[13:8]=x10; V_SCALE[7:0]=0] Vert scale coefficient="none"? -YATTENUATE[2:0]=0 no luma attenuation -YCORING[2:0]=0 Luma-coring bypass -YLPF[1:0]=0 Luma hoz low pass filter=bypass - -***************** */ - -static u16 registers_720_480[] = - { - 0x6e, 0x00, /* HSYNOFFSET[7:0]=0 */ - 0x70, 0x02, /* HSYNOFFSET[9:8]=0; HSYNWIDTH[5:0]=2 */ - 0x72, 0x00, /* VSYNOFFSET[7:0]=0 */ - 0x74, 0x01, /* DATDLY = 0; DATSWP=0; VSYNOFFSET[10:8]=0; VSYNWIDTH[2:0]=1 */ - 0x76, 0xD0, /* H_CLKO[7:0]=xD0 */ - 0x78, 0xD0, /* H_ACTIVE[7:0]=xD0 */ - 0x7a, 0x80, /* HSYNC_WIDTH[7:0]=x80 */ - 0x7c, 0x92, /* HBURST_BEGIN[7:0]=x92 */ - 0x7e, 0x57, /* HBURST_END[7:0]=x57 */ - 0x80, 0x02, /* H_BLANKO[7:0]=x2 */ - 0x82, 0x16, /* V_BLANKO[7:0]=x16 */ - 0x84, 0xF0, /* V_ACTIVEO[7:0]=xF0 */ - 0x86, 0x26, /* V_ACTIVE0[8]=0; H_ACTIVE[9:8]=2; H_CLKO[11:8]=6 */ - 0x88, 0x00, /* H_FRACT[7:0]=0 */ - 0x8a, 0xD0, /* H_CLKI[7:0]=xD0 */ - 0x8c, 0x80, /* H_BLANKI[7:0]=x80 */ - 0x8e, 0x03, /* VBLANKDLY=0; H_BLANKI[8]=0; H_CLKI[10:8]=3 */ - 0x90, 0x0D, /* V_LINESI[7:0]=x0D */ - 0x92, 0x2A, /* V_BLANKI[7:0]=x2A */ - 0x94, 0xE0, /* V_ACTIVEI[7:0]=xE0 */ - 0x96, 0x06, /* CLPF[1:0]=0; YLPF[1:0]=0; V_ACTIVEI[9:8]=1; V_LINESI[9:8]=2 */ - 0x98, 0x00, /* V_SCALE[7:0]=0 */ - 0x9a, 0x50, /* H_BLANKO[9:8]=1; V_SCALE[13:8]=x10 */ - 0x9c, 0x30, /* PLL_FRACT[7:0]=x30 */ - 0x9e, 0x0, /* PLL_FRACT[15:8]=0x0 */ - 0xa0, 0x8c, /* EN_XCLK=1; BY_PLL=0; PLL_INT[5:0]=0x0C */ - 0xa2, 0x0A, /* ECLIP=0; PAL_MD=0; DIS_SCRESET=0; VSYNC_DUR=1; 625LINE=0; SETUP=1; NI_OUT=0 */ - 0xa4, 0xE5, /* SYNC_AMP[7:0]=xE5 */ - 0xa6, 0x74, /* BST_AMP[7:0]=x74 */ - 0xa8, 0x77, /* MCR[7:0]=x77 */ - 0xaa, 0x43, /* MCB[7:0]=x43 */ - 0xac, 0x85, /* MY[7:0]=x85 */ - 0xae, 0xE5, /* MSC[7:0]=xE5 */ - 0xb0, 0x82, /* MSC[15:8]=x82 */ - 0xb2, 0x52, /* MSC[23:16]=x52 */ - 0xb4, 0x21, /* MSC[31:24]=x21 */ - 0xb6, 0x00, /* PHASE_OFF[7:0]=0 */ - //0xba, 0x21, /* SRESET=0; CHECK_STAT=0; SLAVER=1; DACOFF=0; DACDISC=0; DACDISB=0; DACDISA=1 */ - 0xc4, 0x01, /* ESTATUS[1:0]=0; ECCF2=0; ECCF1=0; ECCGATE=0; ECBAR=0; DCHROMA=0; EN_OUT=1 */ - 0xc6, 0x00, /* EN_BLANKO=0; EN_DOT=0; FIELDI=0; VSYNCI=0; HSYNCI=0; IN_MODE[2:0]=0(24bRGB) */ - 0xc8, 0x40, /* DIS_YFLPF=0; DIS_FFILT=1; F_SELC[2:0]=0; F_SELY[2:0]=0 */ - 0xca, 0xc0, /* DIS_GMUSHY=1; DIS_GMSHY=1; YCORING[2:0]=0; YATTENUATE[2:0]=0 */ - 0xcc, 0xc0, /* DIS_GMUSHC=1; DIS_GMSHC=1; CCORING[2:0]=0; CATTENUATE[2:0]=0 */ - //0xce, 0x24, /* OUT_MUXC=2 [C]; OUT_MUXB=1 [Y]; OUT_MUXA=0 [CVBS, but disabled]*/ - //0xce, 0x04, /* OUT_MUXC=0 [CVBS]; OUT_MUXB=1 [Y]; OUT_MUXA=0 [CVBS, but disabled]*/ - 0xd6, 0x00, /* OUT_MODE[1:0]=0; LUMADLY[1:0]=0 */ - 0, 0 - }; - - -static int bt869_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, bt869_detect); -} - -/* This function is called by i2c_detect */ -int bt869_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i, cur; - struct i2c_client *new_client; - struct bt869_data *data; - int err = 0; - const char *type_name, *client_name; - - - printk("bt869.o: probing address %d .\n", address); - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("bt869.o: bt869_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE | - I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access bt869_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct bt869_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &bt869_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. It is lousy. */ - i2c_smbus_write_byte_data(new_client, 0xC4, 0); /* set status bank 0 */ - cur = i2c_smbus_read_byte(new_client); - printk("bt869.o: address 0x%X testing-->0x%X\n", address, cur); - if ((cur & 0xE0) != 0x20) - goto ERROR1; - - /* Determine the chip type */ - kind = ((cur & 0x20) >> 5); - - if (kind) { - type_name = "bt869"; - client_name = "bt869 chip"; - printk("bt869.o: BT869 detected\n"); - } else { - type_name = "bt868"; - client_name = "bt868 chip"; - printk("bt869.o: BT868 detected\n"); - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - bt869_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - bt869_init_client((struct i2c_client *) new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int bt869_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct bt869_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("bt869.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - - -/* All registers are byte-sized. - bt869 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int bt869_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte(client); -} - -/* All registers are byte-sized. - bt869 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int bt869_write_value(struct i2c_client *client, u8 reg, u16 value) -{ -#ifdef DEBUG - printk("bt869.o: write_value(0x%X, 0x%X)\n", reg, value); -#endif - return i2c_smbus_write_byte_data(client, reg, value); -} - -static void bt869_write_values(struct i2c_client *client, u16 *values) -{ - /* writes set of registers from array. 0,0 marks end of table */ - while (*values) { - bt869_write_value(client, values[0], values[1]); - values += 2; - } -} - -static void bt869_init_client(struct i2c_client *client) -{ - struct bt869_data *data = client->data; - - /* Initialize the bt869 chip */ - bt869_write_value(client, 0x0ba, 0x80); - // bt869_write_value(client,0x0D6, 0x00); - /* Be a slave to the clock on the Voodoo3 */ - bt869_write_value(client, 0xa0, 0x80); - bt869_write_value(client, 0xba, 0x20); - /* depth =16bpp */ - bt869_write_value(client, 0x0C6, 0x001); - bt869_write_value(client, 0xC4, 1); - /* Flicker free enable and config */ - bt869_write_value(client, 0xC8, 0); - data->res[0] = 640; - data->res[1] = 480; - data->ntsc = 1; - data->half = 0; - data->colorbars = 0; - data->svideo = 0; - data->depth = 16; - -} - -static void bt869_update_client(struct i2c_client *client) -{ - struct bt869_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { -#ifdef DEBUG - printk("Starting bt869 update\n"); -#endif - if ((data->res[0] == 800) && (data->res[1] == 600)) { - /* 800x600 built-in mode */ - bt869_write_value(client, 0xB8, - (2 + (!data->ntsc))); - bt869_write_value(client, 0xa0, 0x80 + 0x11); - printk("bt869.o: writing into config -->0x%X\n", - (2 + (!data->ntsc))); - } - else if ((data->res[0] == 720) && (data->res[1] == 576)) { - /* 720x576 no-overscan-compensation mode suitable for PAL DVD playback */ - data->ntsc = 0; /* This mode always PAL */ - bt869_write_values(client, registers_720_576); - } - else if ((data->res[0] == 720) && (data->res[1] == 480)) { - /* 720x480 no-overscan-compensation mode suitable for NTSC DVD playback */ - data->ntsc = 1; /* This mode always NTSC */ - bt869_write_values(client, registers_720_480); - } - else { - /* 640x480 built-in mode */ - bt869_write_value(client, 0xB8, (!data->ntsc)); - bt869_write_value(client, 0xa0, 0x80 + 0x0C); - printk("bt869.o: writing into config -->0x%X\n", - (0 + (!data->ntsc))); - if ((data->res[0] != 640) || (data->res[1] != 480)) { - printk - ("bt869.o: Warning: arbitrary resolutions not supported yet. Using 640x480.\n"); - data->res[0] = 640; - data->res[1] = 480; - } - } - /* Set colour depth */ - if ((data->depth != 24) && (data->depth != 16)) - data->depth = 16; - if (data->depth == 16) - bt869_write_value(client, 0x0C6, 0x001); - if (data->depth == 24) - bt869_write_value(client, 0x0C6, 0x000); - /* set "half" resolution mode */ - bt869_write_value(client, 0xd4, data->half << 6); - /* Set composite/svideo mode, also enable the right dacs */ - switch (data->svideo) { - case 2: /* RGB */ - /* requires hardware mod on Voodoo3 to get all outputs, - untested in practice... Feedback to steve@daviesfam.org please */ - bt869_write_value(client, 0xd6, 0x0c); - bt869_write_value(client, 0xce, 0x24); - bt869_write_value(client, 0xba, 0x20); - break; - case 1: /* Svideo*/ - bt869_write_value(client, 0xce, 0x24); - bt869_write_value(client, 0xba, 0x21); - break; - default: /* Composite */ - bt869_write_value(client, 0xce, 0x0); - bt869_write_value(client, 0xba, 0x21); - break; - } - /* Enable outputs */ - bt869_write_value(client, 0xC4, 1); - /* Issue timing reset */ - bt869_write_value(client, 0x6c, 0x80); - -/* Read back status registers */ - bt869_write_value(client, 0xC4, - 1 | (data->colorbars << 2)); - data->status[0] = bt869_read_value(client, 1); - bt869_write_value(client, 0xC4, - 0x41 | (data->colorbars << 2)); - data->status[1] = bt869_read_value(client, 1); - bt869_write_value(client, 0xC4, - 0x81 | (data->colorbars << 2)); - data->status[2] = bt869_read_value(client, 1); - bt869_write_value(client, 0xC4, - 0x0C1 | (data->colorbars << 2)); - data->last_updated = jiffies; - data->valid = 1; - } - up(&data->update_lock); -} - - -void bt869_status(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct bt869_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - bt869_update_client(client); - results[0] = data->status[0]; - results[1] = data->status[1]; - results[2] = data->status[2]; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - printk - ("bt869.o: Warning: write was requested on read-only proc file: status\n"); - } -} - - -void bt869_ntsc(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct bt869_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - bt869_update_client(client); - results[0] = data->ntsc; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->ntsc = (results[0] > 0); - } - bt869_update_client(client); - } -} - - -void bt869_svideo(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct bt869_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - bt869_update_client(client); - results[0] = data->svideo; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->svideo = results[0]; - } - bt869_update_client(client); - } -} - - -void bt869_res(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct bt869_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - bt869_update_client(client); - results[0] = data->res[0]; - results[1] = data->res[1]; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->res[0] = results[0]; - } - if (*nrels_mag >= 2) { - data->res[1] = results[1]; - } - bt869_update_client(client); - } -} - - -void bt869_half(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct bt869_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - bt869_update_client(client); - results[0] = data->half; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->half = (results[0] > 0); - bt869_update_client(client); - } - } -} - -void bt869_colorbars(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct bt869_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - bt869_update_client(client); - results[0] = data->colorbars; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->colorbars = (results[0] > 0); - bt869_update_client(client); - } - } -} - -void bt869_depth(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct bt869_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - bt869_update_client(client); - results[0] = data->depth; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->depth = results[0]; - bt869_update_client(client); - } - } -} - -static int __init sm_bt869_init(void) -{ - printk("bt869.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&bt869_driver); -} - -static void __exit sm_bt869_exit(void) -{ - i2c_del_driver(&bt869_driver); -} - - - -MODULE_AUTHOR - ("Frodo Looijaard , Philip Edelbrock , Stephen Davies "); -MODULE_DESCRIPTION("bt869 driver"); - -module_init(sm_bt869_init); -module_exit(sm_bt869_exit); diff --git a/kernel/chips/ddcmon.c b/kernel/chips/ddcmon.c deleted file mode 100644 index 45303f4b..00000000 --- a/kernel/chips/ddcmon.c +++ /dev/null @@ -1,586 +0,0 @@ -/* - ddcmon.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999, 2000 Frodo Looijaard , - Philip Edelbrock , - and Mark Studebaker - Copyright (c) 2003 Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x50, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(ddcmon); - -static int checksum = 0; -MODULE_PARM(checksum, "i"); -MODULE_PARM_DESC(checksum, "Only accept eeproms whose checksum is correct"); - -/* Many constants specified below */ - -/* DDCMON registers */ -/* vendor section */ -#define DDCMON_REG_MAN_ID 0x08 -#define DDCMON_REG_PROD_ID 0x0A -#define DDCMON_REG_SERIAL 0x0C -#define DDCMON_REG_WEEK 0x10 -#define DDCMON_REG_YEAR 0x11 -/* EDID version */ -#define DDCMON_REG_EDID_VER 0x12 -#define DDCMON_REG_EDID_REV 0x13 -/* display information */ -#define DDCMON_REG_HORSIZE 0x15 -#define DDCMON_REG_VERSIZE 0x16 -#define DDCMON_REG_GAMMA 0x17 -#define DDCMON_REG_DPMS_FLAGS 0x18 -/* supported timings */ -#define DDCMON_REG_ESTABLISHED_TIMINGS 0x23 -#define DDCMON_REG_STANDARD_TIMINGS 0x26 -#define DDCMON_REG_TIMBASE 0x36 -#define DDCMON_REG_TIMINCR 18 -#define DDCMON_REG_TIMNUM 4 - -#define DDCMON_REG_CHECKSUM 0x7f - -/* Size of DDCMON in bytes */ -#define DDCMON_SIZE 128 - -/* Each client has this additional data */ -struct ddcmon_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 data[DDCMON_SIZE]; /* Register values */ -}; - - -static int ddcmon_attach_adapter(struct i2c_adapter *adapter); -static int ddcmon_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int ddcmon_detach_client(struct i2c_client *client); - -static void ddcmon_idcall(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_size(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_sync(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_maxclock(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_timings(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_serial(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_time(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_edid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_gamma(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_dpms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_standard_timing(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ddcmon_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver ddcmon_driver = { - .name = "DDCMON READER", - .id = I2C_DRIVERID_DDCMON, - .flags = I2C_DF_NOTIFY, - .attach_adapter = ddcmon_attach_adapter, - .detach_client = ddcmon_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define DDCMON_SYSCTL_ID 1010 -#define DDCMON_SYSCTL_SIZE 1011 -#define DDCMON_SYSCTL_SYNC 1012 -#define DDCMON_SYSCTL_TIMINGS 1013 -#define DDCMON_SYSCTL_SERIAL 1014 -#define DDCMON_SYSCTL_TIME 1015 -#define DDCMON_SYSCTL_EDID 1016 -#define DDCMON_SYSCTL_GAMMA 1017 -#define DDCMON_SYSCTL_DPMS 1018 -#define DDCMON_SYSCTL_TIMING1 1021 -#define DDCMON_SYSCTL_TIMING2 1022 -#define DDCMON_SYSCTL_TIMING3 1023 -#define DDCMON_SYSCTL_TIMING4 1024 -#define DDCMON_SYSCTL_TIMING5 1025 -#define DDCMON_SYSCTL_TIMING6 1026 -#define DDCMON_SYSCTL_TIMING7 1027 -#define DDCMON_SYSCTL_TIMING8 1028 -#define DDCMON_SYSCTL_MAXCLOCK 1029 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected DDCMON. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table ddcmon_dir_table_template[] = { - {DDCMON_SYSCTL_ID, "id", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &ddcmon_idcall}, - {DDCMON_SYSCTL_SIZE, "size", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &ddcmon_size}, - {DDCMON_SYSCTL_SYNC, "sync", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_sync}, - {DDCMON_SYSCTL_TIMINGS, "timings", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_timings}, - {DDCMON_SYSCTL_SERIAL, "serial", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_serial}, - {DDCMON_SYSCTL_TIME, "time", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_time}, - {DDCMON_SYSCTL_EDID, "edid", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_edid}, - {DDCMON_SYSCTL_GAMMA, "gamma", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_gamma}, - {DDCMON_SYSCTL_DPMS, "dpms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_dpms}, - {DDCMON_SYSCTL_TIMING1, "timing1", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing}, - {DDCMON_SYSCTL_TIMING2, "timing2", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing}, - {DDCMON_SYSCTL_TIMING3, "timing3", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing}, - {DDCMON_SYSCTL_TIMING4, "timing4", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing}, - {DDCMON_SYSCTL_TIMING5, "timing5", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing}, - {DDCMON_SYSCTL_TIMING6, "timing6", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing}, - {DDCMON_SYSCTL_TIMING7, "timing7", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing}, - {DDCMON_SYSCTL_TIMING8, "timing8", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing}, - {DDCMON_SYSCTL_MAXCLOCK, "maxclock", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_maxclock}, - {0} -}; - -static int ddcmon_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, ddcmon_detect); -} - -/* This function is called by i2c_detect */ -int ddcmon_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i, cs; - struct i2c_client *new_client; - struct ddcmon_data *data; - int err = 0; - const char *type_name, *client_name; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access ddcmon_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct ddcmon_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - memset(data->data, 0xff, DDCMON_SIZE); - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &ddcmon_driver; - new_client->flags = 0; - - /* prevent 24RF08 corruption (just in case) */ - i2c_smbus_write_quick(new_client, 0); - - /* Now, we do the remaining detection. */ - if (checksum) { - int cs = 0; - for (i = 0; i < 0x80; i++) - cs += i2c_smbus_read_byte_data(new_client, i); - if ((cs & 0xff) != 0) - goto ERROR1; - } - - /* Verify the first 8 locations 0x00FFFFFFFFFFFF00 */ - /* Allow force and force_ddcmon arguments */ - if(kind < 0) - { - for(i = 0; i < 8; i++) { - cs = i2c_smbus_read_byte_data(new_client, i); - if(i == 0 || i == 7) { - if(cs != 0) - goto ERROR1; - } else if(cs != 0xff) - goto ERROR1; - } - } - - type_name = "ddcmon"; - client_name = "DDC Monitor"; - - /* Fill in the remaining client fields and put it in the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - ddcmon_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - return 0; - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int ddcmon_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct ddcmon_data *) (client->data))-> - sysctl_id); - if ((err = i2c_detach_client(client))) { - printk - ("ddcmon.o: Client deregistration failed, client not detached.\n"); - return err; - } - kfree(client->data); - return 0; -} - -static void ddcmon_update_client(struct i2c_client *client) -{ - struct ddcmon_data *data = client->data; - int i, j; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 300 * HZ) || - (jiffies < data->last_updated) || !data->valid) { - if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_I2C_BLOCK)) - { - for (i=0; idata + i) - != I2C_SMBUS_I2C_BLOCK_MAX) { - printk(KERN_WARNING "ddcmon.o: block read fail at 0x%.2x!\n", i); - goto DONE; - } - } else { - if (i2c_smbus_write_byte(client, 0)) { - printk(KERN_WARNING "ddcmon.o: read start fail at 0!\n"); - goto DONE; - } - for (i = 0; i < DDCMON_SIZE; i++) { - j = i2c_smbus_read_byte(client); - if (j < 0) { - printk(KERN_WARNING "eeprom.o: read fail at 0x%.2x!\n", i); - goto DONE; - } - data->data[i] = (u8) j; - } - } - data->last_updated = jiffies; - data->valid = 1; - } -DONE: - up(&data->update_lock); -} - - -void ddcmon_idcall(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - results[0] = data->data[DDCMON_REG_MAN_ID + 1] | - (data->data[DDCMON_REG_MAN_ID] << 8); - results[1] = data->data[DDCMON_REG_PROD_ID + 1] | - (data->data[DDCMON_REG_PROD_ID] << 8); - *nrels_mag = 2; - } -} - -void ddcmon_size(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - results[0] = data->data[DDCMON_REG_VERSIZE]; - results[1] = data->data[DDCMON_REG_HORSIZE]; - *nrels_mag = 2; - } -} - -void ddcmon_sync(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - int i, j; - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - *nrels_mag = 4; - /* look for monitor limits entry */ - for(i = DDCMON_REG_TIMBASE; - i < DDCMON_REG_TIMBASE + - (DDCMON_REG_TIMNUM * DDCMON_REG_TIMINCR); - i += DDCMON_REG_TIMINCR) { - if (data->data[i] == 0x00 - && data->data[i + 1] == 0x00 - && data->data[i + 2] == 0x00 - && data->data[i + 3] == 0xfd) { - for(j = 0; j < 4; j++) - results[j] = data->data[i + j + 5]; - return; - } - } - for(j = 0; j < 4; j++) - results[j] = 0; - } -} - -void ddcmon_maxclock(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - int i; - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - *nrels_mag = 1; - /* look for monitor limits entry */ - for(i = DDCMON_REG_TIMBASE; - i < DDCMON_REG_TIMBASE + - (DDCMON_REG_TIMNUM * DDCMON_REG_TIMINCR); - i += DDCMON_REG_TIMINCR) { - if (data->data[i] == 0x00 - && data->data[i + 1] == 0x00 - && data->data[i + 2] == 0x00 - && data->data[i + 3] == 0xfd) { - results[0] = (data->data[i + 9] == 0xff ? - 0 : data->data[i + 9] * 10); - return; - } - } - results[0] = 0; - } -} - -void ddcmon_timings(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - results[0] = data->data[DDCMON_REG_ESTABLISHED_TIMINGS] | - (data->data[DDCMON_REG_ESTABLISHED_TIMINGS + 1] << 8) | - (data->data[DDCMON_REG_ESTABLISHED_TIMINGS + 2] << 16); - *nrels_mag = 1; - } -} - -void ddcmon_serial(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - results[0] = data->data[DDCMON_REG_SERIAL] | - (data->data[DDCMON_REG_SERIAL + 1] << 8) | - (data->data[DDCMON_REG_SERIAL + 2] << 16) | - (data->data[DDCMON_REG_SERIAL + 3] << 24); - *nrels_mag = 1; - } -} - -void ddcmon_time(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - results[0] = data->data[DDCMON_REG_YEAR] + 1990; - results[1] = data->data[DDCMON_REG_WEEK]; - *nrels_mag = 2; - } -} - -void ddcmon_edid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - results[0] = data->data[DDCMON_REG_EDID_VER]; - results[1] = data->data[DDCMON_REG_EDID_REV]; - *nrels_mag = 2; - } -} - -void ddcmon_gamma(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - results[0] = 100 + data->data[DDCMON_REG_GAMMA]; - *nrels_mag = 1; - } -} - -void ddcmon_dpms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ddcmon_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - results[0] = data->data[DDCMON_REG_DPMS_FLAGS]; - *nrels_mag = 1; - } -} - -void ddcmon_standard_timing(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ddcmon_data *data = client->data; - int nr = ctl_name - DDCMON_SYSCTL_TIMING1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ddcmon_update_client(client); - /* If both bytes of the timing are 0x00 or 0x01, then the timing - slot is unused. */ - if ((data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2] - | data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2 + 1]) & 0xfe) { - results[0] = (data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2] + 31) * 8; - switch (data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2 + 1] >> 6) { - /* We don't care about rounding issues there, it really - should be OK without it. */ - case 0x00: - results[1] = results[0]; /* unconfirmed */ - break; - case 0x01: - results[1] = results[0] * 3 / 4; - break; - case 0x02: - results[1] = results[0] * 4 / 5; - break; - case 0x03: - results[1] = results[0] * 9 / 16; - break; - } - results[2] = (data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2 + 1] & 0x3f) + 60; - } else { - results[0] = 0; - results[1] = 0; - results[2] = 0; - } - *nrels_mag = 3; - } -} - -static int __init sm_ddcmon_init(void) -{ - printk("ddcmon.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&ddcmon_driver); -} - -static void __exit sm_ddcmon_exit(void) -{ - i2c_del_driver(&ddcmon_driver); -} - - - -MODULE_AUTHOR("Frodo Looijaard , " - "Philip Edelbrock , " - "Mark Studebaker " - "and Jean Delvare "); -MODULE_DESCRIPTION("DDCMON driver"); - -module_init(sm_ddcmon_init); -module_exit(sm_ddcmon_exit); diff --git a/kernel/chips/ds1307.c b/kernel/chips/ds1307.c deleted file mode 100644 index 028e6ceb..00000000 --- a/kernel/chips/ds1307.c +++ /dev/null @@ -1,345 +0,0 @@ - -/* - * linux/drivers/i2c/ds1307.c - * - * Author: Abraham van der Merwe - * - * Linux support for the Dallas Semiconductor DS1307 Serial Real-Time - * Clock. - * - * Based on code from the lm-sensors project which is available - * at http://www.lm-sensors.org/ and Russell King's PCF8583 Real-Time - * Clock driver (linux/drivers/acorn/char/pcf8583.c). - * - * This source code is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "ds1307.h" - -#define BCD_TO_BIN(x) (((x) & 15) + ((x) >> 4) * 10) -#define BIN_TO_BCD(x) ((((x) / 10) << 4) + (x) % 10) - -static struct i2c_driver ds1307; -static DECLARE_MUTEX (mutex); - -/* - * The DS1307 Real-Time Clock wants the address in a different - * message, so we can't use the normal i2c_master_recv() routine - * for receiving data. - */ -static int ds1307_i2c_recv (struct i2c_client *client,char *buf,char addr,int count) -{ - struct i2c_msg msg[] = { - { addr: client->addr, flags: 0, len: 1, buf: &addr }, - { addr: client->addr, flags: I2C_M_RD, len: count, buf: buf } - }; - int result = 0; - - if (down_interruptible (&mutex)) - return (-ERESTARTSYS); - - if (i2c_transfer (client->adapter,msg,2) != 2) - result = -EIO; - - up (&mutex); - - return (result); -} - -/* - * Would've been nice to specify the address to this as well, but then we - * would need to copy the buffer twice - not worth it... - */ -static int ds1307_i2c_send (struct i2c_client *client,const char *buf,int count) -{ - int result = 0; - - if (down_interruptible (&mutex)) - return (-ERESTARTSYS); - - if (i2c_master_send (client,(const char *) buf,count) != count) - result = -EIO; - - up (&mutex); - - return (result); -} - -static int ds1307_attach (struct i2c_adapter *adapter,int addr,unsigned short flags,int kind) -{ - struct i2c_client *client; - int result; - - if ((client = (struct i2c_client *) kmalloc (sizeof (struct i2c_client),GFP_KERNEL)) == NULL) - return (-ENOMEM); - - strcpy (client->name,ds1307.name); - client->flags = I2C_CLIENT_ALLOW_USE | I2C_CLIENT_ALLOW_MULTIPLE_USE; - client->addr = addr; - client->adapter = adapter; - client->driver = &ds1307; - client->data = NULL; - - if ((result = i2c_attach_client (client))) { - kfree (client); - return (result); - } - - return (0); -} - -static int ds1307_attach_adapter (struct i2c_adapter *adapter) -{ - static unsigned short ignore[] = { I2C_CLIENT_END }; - static unsigned short addr[] = { 0x68, I2C_CLIENT_END }; - static struct i2c_client_address_data ds1307_addr_data = { - normal_i2c: addr, - normal_i2c_range: ignore, - probe: ignore, - probe_range: ignore, - ignore: ignore, - ignore_range: ignore, - force: ignore - }; - - return (i2c_probe (adapter,&ds1307_addr_data,ds1307_attach)); -} - -static int ds1307_detach_client (struct i2c_client *client) -{ - int result; - - if ((result = i2c_detach_client (client))) - return (result); - - kfree (client); - - return (0); -} - -static int ds1307_getdate (struct i2c_client *client,void *arg) -{ - struct ds1307_date *date = (struct ds1307_date *) arg; - u8 buf[7]; - - /* this also enables the oscillator */ - memset (buf,0,7); - - /* enable 24-hour mode */ - buf[2] = 0x40; - - if (ds1307_i2c_recv (client,(char *) buf,0,7) < 0) - return (-EIO); - - date->tm_sec = BCD_TO_BIN (buf[0] & ~0x80); - date->tm_min = BCD_TO_BIN (buf[1]); - date->tm_hour = BCD_TO_BIN (buf[2] & 0x3f); - date->tm_wday = BCD_TO_BIN (buf[3]) - 1; - date->tm_mday = BCD_TO_BIN (buf[4]); - date->tm_mon = BCD_TO_BIN (buf[5]) - 1; - date->tm_year = BCD_TO_BIN (buf[6]) + 100; - - return (0); -} - -static int ds1307_setdate (struct i2c_client *client,void *arg) -{ - struct ds1307_date *date = (struct ds1307_date *) arg; - u8 buf[8]; - - /* select address 0 */ - buf[0] = 0; - - buf[1] = BIN_TO_BCD (date->tm_sec); - buf[2] = BIN_TO_BCD (date->tm_min); - buf[3] = BIN_TO_BCD (date->tm_hour) | 0x40; - buf[4] = BIN_TO_BCD (date->tm_wday + 1); - buf[5] = BIN_TO_BCD (date->tm_mday); - buf[6] = BIN_TO_BCD (date->tm_mon + 1); - buf[7] = BIN_TO_BCD (date->tm_year - 100); - - return (ds1307_i2c_send (client,(const char *) buf,8)); -} - -static int ds1307_enable (struct i2c_client *client,void *arg) -{ - u8 buf[2]; - - if (ds1307_i2c_recv (client,(char *) buf + 1,0,1) < 0) - return (-EIO); - - if ((buf[1] & 0x80)) { - buf[0] = 0, buf[1] &= ~0x80; - return (ds1307_i2c_send (client,(const char *) buf,2)); - } - - return (0); -} - -static int ds1307_irqon (struct i2c_client *client,void *arg) -{ - u8 buf[2]; - - if (ds1307_i2c_recv (client,(char *) buf + 1,7,1) < 0) - return (-EIO); - - buf[0] = 7; - buf[1] |= 0x10; - - return (ds1307_i2c_send (client,(const char *) buf,2)); -} - -static int ds1307_irqoff (struct i2c_client *client,void *arg) -{ - u8 buf[2]; - - if (ds1307_i2c_recv (client,(char *) buf + 1,7,1) < 0) - return (-EIO); - - buf[0] = 7; - buf[1] &= ~0x10; - - return (ds1307_i2c_send (client,(const char *) buf,2)); -} - -static int ds1307_getfreq (struct i2c_client *client,void *arg) -{ - u16 *freq = (u16 *) arg; - u8 buf; - static const u16 table[] = { - DS1307_FREQ_1HZ, - DS1307_FREQ_4KHZ, - DS1307_FREQ_8KHZ, - DS1307_FREQ_32KHZ - }; - - if (ds1307_i2c_recv (client,(char *) &buf,7,1) < 0) - return (-EIO); - - *freq = table[buf & 3]; - - return (0); -} - -static int ds1307_setfreq (struct i2c_client *client,void *arg) -{ - u16 *freq = (u16 *) arg; - u8 buf[2]; - - /* select address 7 */ - buf[0] = 7; - - /* default to 1HZ */ - buf[1] = 0; - - switch (*freq) { - case DS1307_FREQ_32KHZ: buf[1]++; - case DS1307_FREQ_8KHZ: buf[1]++; - case DS1307_FREQ_4KHZ: buf[1]++; - case DS1307_FREQ_1HZ: break; - default: - return (-EINVAL); - } - - return (ds1307_i2c_send (client,(const char *) buf,2)); -} - -static int ds1307_read (struct i2c_client *client,void *arg) -{ - struct ds1307_memory *mem = (struct ds1307_memory *) arg; - u8 buf[DS1307_SIZE]; - - if (mem->offset >= DS1307_SIZE || mem->offset + mem->length > DS1307_SIZE) - return (-EINVAL); - - if (ds1307_i2c_recv (client,(char *) buf,mem->offset + 8,mem->length) < 0) - return (-EIO); - - memcpy (mem->buf,buf,mem->length); - - return (0); -} - -static int ds1307_write (struct i2c_client *client,void *arg) -{ - struct ds1307_memory *mem = (struct ds1307_memory *) arg; - u8 buf[DS1307_SIZE + 1]; - - if (mem->offset >= DS1307_SIZE || mem->offset + mem->length > DS1307_SIZE) - return (-EINVAL); - - buf[0] = mem->offset + 8; - - memcpy (buf + 1,mem->buf,mem->length); - - return (ds1307_i2c_send (client,(const char *) buf,mem->length + 1)); -} - -static int ds1307_command (struct i2c_client *client,unsigned int cmd,void *arg) -{ - static const struct { - int cmd; - int (*function) (struct i2c_client *,void *arg); - } ioctl[] = { - { DS1307_ENABLE, ds1307_enable }, - { DS1307_GET_DATE, ds1307_getdate }, - { DS1307_SET_DATE, ds1307_setdate }, - { DS1307_IRQ_ON, ds1307_irqon }, - { DS1307_IRQ_OFF, ds1307_irqoff }, - { DS1307_GET_FREQ, ds1307_getfreq }, - { DS1307_SET_FREQ, ds1307_setfreq }, - { DS1307_READ, ds1307_read }, - { DS1307_WRITE, ds1307_write } - }; - int i; - - for (i = 0; i < sizeof (ioctl) / sizeof (ioctl[0]); i++) - if (ioctl[i].cmd == cmd) - return (ioctl[i].function (client,arg)); - - return (-EINVAL); -} - - -static struct i2c_driver ds1307 = { - .name = "ds1307", - .id = I2C_DRIVERID_DS1307, - .flags = I2C_DF_NOTIFY, - .attach_adapter = ds1307_attach_adapter, - .detach_client = ds1307_detach_client, - .command = ds1307_command, -}; - -static int __init sm_ds1307_init(void) -{ - printk("ds1307.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&ds1307); -} - -static void __exit sm_ds1307_exit(void) -{ - i2c_del_driver(&ds1307); -} - - - -MODULE_AUTHOR ("Abraham van der Merwe "); -MODULE_DESCRIPTION ("Linux support for DS1307 Real-Time Clock"); - -MODULE_LICENSE ("GPL"); - -module_init(sm_ds1307_init); -module_exit(sm_ds1307_exit); - diff --git a/kernel/chips/ds1621.c b/kernel/chips/ds1621.c deleted file mode 100644 index 9586d044..00000000 --- a/kernel/chips/ds1621.c +++ /dev/null @@ -1,537 +0,0 @@ -/* - ds1621.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Christian W. Zuckschwerdt 2000-11-23 - based on lm75.c by Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* Supports DS1621. See doc/chips/ds1621 for details */ - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x48, 0x4f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(ds1621); - -/* Many DS1621 constants specified below */ - -/* Config register used for detection */ -/* 7 6 5 4 3 2 1 0 */ -/* |Done|THF |TLF |NVB | X | X |POL |1SHOT| */ -#define DS1621_REG_CONFIG_NVB 0x10 -#define DS1621_REG_CONFIG_POLARITY 0x02 -#define DS1621_REG_CONFIG_1SHOT 0x01 -#define DS1621_REG_CONFIG_DONE 0x80 - -/* Note: the done bit is always unset if continuous conversion is in progress. - We need to stop the continuous conversion or switch to single shot - before this bit becomes available! - */ - -/* The DS1621 registers */ -#define DS1621_REG_TEMP 0xAA /* word, RO */ -#define DS1621_REG_TEMP_OVER 0xA1 /* word, RW */ -#define DS1621_REG_TEMP_HYST 0xA2 /* word, RW -- it's a low temp trigger */ -#define DS1621_REG_CONF 0xAC /* byte, RW */ -#define DS1621_REG_TEMP_COUNTER 0xA8 /* byte, RO */ -#define DS1621_REG_TEMP_SLOPE 0xA9 /* byte, RO */ -#define DS1621_COM_START 0xEE /* no data */ -#define DS1621_COM_STOP 0x22 /* no data */ - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define TEMP_FROM_REG(val) ((((val & 0x7fff) >> 7) * 5) | \ - ((val & 0x8000)?-256:0)) -#define TEMP_TO_REG(val) (SENSORS_LIMIT((val<0 ? (0x200+((val)/5))<<7 : \ - (((val) + 2) / 5) << 7),0,0xffff)) -#define ALARMS_FROM_REG(val) ((val) & \ - (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW)) -#define ITEMP_FROM_REG(val) ((((val & 0x7fff) >> 8)) | \ - ((val & 0x8000)?-256:0)) - -/* Each client has this additional data */ -struct ds1621_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u16 temp, temp_over, temp_hyst; /* Register values, word */ - u8 conf; /* Register encoding, combined */ - - char enable; /* !=0 if we're expected to restart the conversion */ - u8 temp_int, temp_counter, temp_slope; /* Register values, byte */ -}; - -static int ds1621_attach_adapter(struct i2c_adapter *adapter); -static int ds1621_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void ds1621_init_client(struct i2c_client *client); -static int ds1621_detach_client(struct i2c_client *client); - -static int ds1621_read_value(struct i2c_client *client, u8 reg); -static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value); -static void ds1621_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ds1621_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ds1621_enable(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ds1621_continuous(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ds1621_polarity(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ds1621_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver ds1621_driver = { - .name = "DS1621 sensor driver", - .id = I2C_DRIVERID_DS1621, - .flags = I2C_DF_NOTIFY, - .attach_adapter = ds1621_attach_adapter, - .detach_client = ds1621_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define DS1621_SYSCTL_TEMP 1200 /* Degrees Celsius * 10 */ -#define DS1621_SYSCTL_ALARMS 2001 /* bitvector */ -#define DS1621_ALARM_TEMP_HIGH 0x40 -#define DS1621_ALARM_TEMP_LOW 0x20 -#define DS1621_SYSCTL_ENABLE 2002 -#define DS1621_SYSCTL_CONTINUOUS 2003 -#define DS1621_SYSCTL_POLARITY 2004 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected DS1621. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table ds1621_dir_table_template[] = { - {DS1621_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_temp}, - {DS1621_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_alarms}, - {DS1621_SYSCTL_ENABLE, "enable", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_enable}, - {DS1621_SYSCTL_CONTINUOUS, "continuous", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_continuous}, - {DS1621_SYSCTL_POLARITY, "polarity", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_polarity}, - {0} -}; - -static int ds1621_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, ds1621_detect); -} - -/* This function is called by i2c_detect */ -static int ds1621_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i, conf, temp; - struct i2c_client *new_client; - struct ds1621_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("ds1621.o: ds1621_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_WRITE_BYTE)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access ds1621_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct ds1621_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &ds1621_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. It is lousy. */ - if (kind < 0) { - /* The NVB bit should be low if no EEPROM write has been - requested during the latest 10ms, which is highly - improbable in our case. */ - conf = i2c_smbus_read_byte_data(new_client, - DS1621_REG_CONF); - if (conf & DS1621_REG_CONFIG_NVB) - goto ERROR1; - /* The 7 lowest bits of a temperature should always be 0. */ - temp = ds1621_read_value(new_client, - DS1621_REG_TEMP); - if (temp & 0x007f) - goto ERROR1; - temp = ds1621_read_value(new_client, - DS1621_REG_TEMP_HYST); - if (temp & 0x007f) - goto ERROR1; - temp = ds1621_read_value(new_client, - DS1621_REG_TEMP_OVER); - if (temp & 0x007f) - goto ERROR1; - } - - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = ds1621; - - if (kind == ds1621) { - type_name = "ds1621"; - client_name = "DS1621 chip"; - } else { -#ifdef DEBUG - printk("ds1621.o: Internal error: unknown kind (%d)?!?", - kind); -#endif - goto ERROR1; - } - - /* Fill in remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - ds1621_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - ds1621_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int ds1621_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct ds1621_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("ds1621.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - - -/* All registers are word-sized, except for the configuration register. - DS1621 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int ds1621_read_value(struct i2c_client *client, u8 reg) -{ - if ((reg == DS1621_REG_CONF) || (reg == DS1621_REG_TEMP_COUNTER) - || (reg == DS1621_REG_TEMP_SLOPE)) - return i2c_smbus_read_byte_data(client, reg); - else - return swab16(i2c_smbus_read_word_data(client, reg)); -} - -/* All registers are word-sized, except for the configuration register. - DS1621 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if ( (reg == DS1621_COM_START) || (reg == DS1621_COM_STOP) ) - return i2c_smbus_write_byte(client, reg); - else - if ((reg == DS1621_REG_CONF) || (reg == DS1621_REG_TEMP_COUNTER) - || (reg == DS1621_REG_TEMP_SLOPE)) - return i2c_smbus_write_byte_data(client, reg, value); - else - return i2c_smbus_write_word_data(client, reg, swab16(value)); -} - -static void ds1621_init_client(struct i2c_client *client) -{ - int reg; - - reg = ds1621_read_value(client, DS1621_REG_CONF); - /* start the continuous conversion */ - if(reg & 0x01) - ds1621_write_value(client, DS1621_REG_CONF, reg & 0xfe); -} - -static void ds1621_update_client(struct i2c_client *client) -{ - struct ds1621_data *data = client->data; - u8 new_conf; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting ds1621 update\n"); -#endif - - data->conf = ds1621_read_value(client, DS1621_REG_CONF); - - data->temp = ds1621_read_value(client, - DS1621_REG_TEMP); - data->temp_over = ds1621_read_value(client, - DS1621_REG_TEMP_OVER); - data->temp_hyst = ds1621_read_value(client, - DS1621_REG_TEMP_HYST); - - /* wait for the DONE bit before reading extended values */ - - if (data->conf & DS1621_REG_CONFIG_DONE) { - data->temp_counter = ds1621_read_value(client, - DS1621_REG_TEMP_COUNTER); - data->temp_slope = ds1621_read_value(client, - DS1621_REG_TEMP_SLOPE); - data->temp_int = ITEMP_FROM_REG(data->temp); - /* restart the conversion */ - if (data->enable) - ds1621_write_value(client, DS1621_COM_START, 0); - } - - /* reset alarms if necessary */ - new_conf = data->conf; - if (data->temp < data->temp_over) - new_conf &= ~DS1621_ALARM_TEMP_HIGH; - if (data->temp > data->temp_hyst) - new_conf &= ~DS1621_ALARM_TEMP_LOW; - if (data->conf != new_conf) - ds1621_write_value(client, DS1621_REG_CONF, - new_conf); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void ds1621_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct ds1621_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - if (!(data->conf & DS1621_REG_CONFIG_DONE) || - (data->temp_counter > data->temp_slope) || - (data->temp_slope == 0)) { - *nrels_mag = 1; - } else { - *nrels_mag = 2; - } - else if (operation == SENSORS_PROC_REAL_READ) { - ds1621_update_client(client); - /* decide wether to calculate more precise temp */ - if (!(data->conf & DS1621_REG_CONFIG_DONE) || - (data->temp_counter > data->temp_slope) || - (data->temp_slope == 0)) { - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - } else { - results[0] = TEMP_FROM_REG(data->temp_over)*10; - results[1] = TEMP_FROM_REG(data->temp_hyst)*10; - results[2] = data->temp_int * 100 - 25 + - ((data->temp_slope - data->temp_counter) * - 100 / data->temp_slope); - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over = TEMP_TO_REG(results[0]); - ds1621_write_value(client, DS1621_REG_TEMP_OVER, - data->temp_over); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - ds1621_write_value(client, DS1621_REG_TEMP_HYST, - data->temp_hyst); - } - } -} - -void ds1621_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct ds1621_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ds1621_update_client(client); - results[0] = ALARMS_FROM_REG(data->conf); - *nrels_mag = 1; - } -} - -void ds1621_enable(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - /* If you really screw up your chip (like I did) this is */ - /* sometimes needed to (re)start the continuous conversion */ - /* there is no data to read so this might hang your SMBus! */ - - struct ds1621_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ds1621_update_client(client); - results[0] = !(data->conf & DS1621_REG_CONFIG_DONE); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (results[0]) { - ds1621_write_value(client, DS1621_COM_START, 0); - data->enable=1; - } else { - ds1621_write_value(client, DS1621_COM_STOP, 0); - data->enable=0; - } - } else { - ds1621_write_value(client, DS1621_COM_START, 0); - data->enable=1; - } - } -} - -void ds1621_continuous(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct ds1621_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ds1621_update_client(client); - results[0] = !(data->conf & DS1621_REG_CONFIG_1SHOT); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - ds1621_update_client(client); - if (*nrels_mag >= 1) { - if (results[0]) { - ds1621_write_value(client, DS1621_REG_CONF, - data->conf & ~DS1621_REG_CONFIG_1SHOT); - } else { - ds1621_write_value(client, DS1621_REG_CONF, - data->conf | DS1621_REG_CONFIG_1SHOT); - } - } else { - ds1621_write_value(client, DS1621_REG_CONF, - data->conf & ~DS1621_REG_CONFIG_1SHOT); - } - } -} - -void ds1621_polarity(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct ds1621_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ds1621_update_client(client); - results[0] = !(!(data->conf & DS1621_REG_CONFIG_POLARITY)); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - ds1621_update_client(client); - if (*nrels_mag >= 1) { - if (results[0]) { - ds1621_write_value(client, DS1621_REG_CONF, - data->conf | DS1621_REG_CONFIG_POLARITY); - } else { - ds1621_write_value(client, DS1621_REG_CONF, - data->conf & ~DS1621_REG_CONFIG_POLARITY); - } - } - } -} - -static int __init sm_ds1621_init(void) -{ - printk("ds1621.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&ds1621_driver); -} - -static void __exit sm_ds1621_exit(void) -{ - i2c_del_driver(&ds1621_driver); -} - - - -MODULE_AUTHOR("Christian W. Zuckschwerdt "); -MODULE_DESCRIPTION("DS1621 driver"); - -module_init(sm_ds1621_init); -module_exit(sm_ds1621_exit); diff --git a/kernel/chips/eeprom.c b/kernel/chips/eeprom.c deleted file mode 100644 index 15f00940..00000000 --- a/kernel/chips/eeprom.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - eeprom.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard and - Philip Edelbrock - - 2003-08-18 Jean Delvare - Divide the eeprom in 2-row (arbitrary) slices. This significantly - speeds sensors up, as well as various scripts using the eeprom - module. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include /* for capable() */ -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x50, 0x57, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(eeprom); - - -/* possible natures */ -#define NATURE_UNKNOWN 0 -#define NATURE_VAIO 1 - -/* Size of EEPROM in bytes */ -#define EEPROM_SIZE 256 - -/* Each client has this additional data */ -struct eeprom_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - u8 valid; /* bitfield, bit!=0 if slice is valid */ - unsigned long last_updated[8]; /* In jiffies, 8 slices */ - - u8 data[EEPROM_SIZE]; /* Register values */ - u8 nature; -}; - - -static int eeprom_attach_adapter(struct i2c_adapter *adapter); -static int eeprom_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int eeprom_detach_client(struct i2c_client *client); - -#if 0 -static int eeprom_write_value(struct i2c_client *client, u8 reg, - u8 value); -#endif - -static void eeprom_contents(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void eeprom_update_client(struct i2c_client *client, u8 slice); - - -/* This is the driver that will be inserted */ -static struct i2c_driver eeprom_driver = { - .name = "EEPROM READER", - .id = I2C_DRIVERID_EEPROM, - .flags = I2C_DF_NOTIFY, - .attach_adapter = eeprom_attach_adapter, - .detach_client = eeprom_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define EEPROM_SYSCTL1 1000 -#define EEPROM_SYSCTL2 1001 -#define EEPROM_SYSCTL3 1002 -#define EEPROM_SYSCTL4 1003 -#define EEPROM_SYSCTL5 1004 -#define EEPROM_SYSCTL6 1005 -#define EEPROM_SYSCTL7 1006 -#define EEPROM_SYSCTL8 1007 -#define EEPROM_SYSCTL9 1008 -#define EEPROM_SYSCTL10 1009 -#define EEPROM_SYSCTL11 1010 -#define EEPROM_SYSCTL12 1011 -#define EEPROM_SYSCTL13 1012 -#define EEPROM_SYSCTL14 1013 -#define EEPROM_SYSCTL15 1014 -#define EEPROM_SYSCTL16 1015 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected EEPROM. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table eeprom_dir_table_template[] = { - {EEPROM_SYSCTL1, "00", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL2, "10", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL3, "20", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL4, "30", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL5, "40", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL6, "50", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL7, "60", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL8, "70", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL9, "80", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL10, "90", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL11, "a0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL12, "b0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL13, "c0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL14, "d0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL15, "e0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {EEPROM_SYSCTL16, "f0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &eeprom_contents}, - {0} -}; - -static int eeprom_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, eeprom_detect); -} - -/* This function is called by i2c_detect */ -static int eeprom_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct eeprom_data *data; - int err = 0; - const char *type_name; - - /* There are three ways we can read the EEPROM data: - (1) I2C block reads (faster, but unsupported by most adapters) - (2) Consecutive byte reads (100% overhead) - (3) Regular byte data reads (200% overhead) - The third method is not implemented by this driver because all - known adapters support at least the second. */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA - | I2C_FUNC_SMBUS_BYTE)) - goto ERROR0; - - if (!(data = kmalloc(sizeof(struct eeprom_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - memset(data->data, 0xff, EEPROM_SIZE); - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &eeprom_driver; - new_client->flags = 0; - - /* prevent 24RF08 corruption */ - i2c_smbus_write_quick(new_client, 0); - - type_name = "eeprom"; - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, "EEPROM chip"); - data->valid = 0; - init_MUTEX(&data->update_lock); - data->nature = NATURE_UNKNOWN; - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Detect the Vaio nature of EEPROMs. - We use the "PCG-" prefix as the signature. */ - if (address == 0x57) { - if (i2c_smbus_read_byte_data(new_client, 0x80) == 'P' - && i2c_smbus_read_byte(new_client) == 'C' - && i2c_smbus_read_byte(new_client) == 'G' - && i2c_smbus_read_byte(new_client) == '-') { - printk(KERN_INFO "Vaio EEPROM detected, " - "enabling password protection\n"); - data->nature = NATURE_VAIO; - } - } - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - eeprom_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - return 0; - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - kfree(data); - ERROR0: - return err; -} - -static int eeprom_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct eeprom_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("eeprom.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - - -#if 0 -/* No writes yet (PAE) */ -static int eeprom_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} -#endif - -static void eeprom_update_client(struct i2c_client *client, u8 slice) -{ - struct eeprom_data *data = client->data; - int i, j; - - down(&data->update_lock); - - if (!(data->valid & (1 << slice)) - || (jiffies - data->last_updated[slice] > 300 * HZ) - || (jiffies < data->last_updated[slice])) { - -#ifdef DEBUG - printk(KERN_DEBUG "eeprom.o: Starting update, slice %u\n", slice); -#endif - - if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_I2C_BLOCK)) - { - for (i = slice << 5; i < (slice + 1) << 5; - i += I2C_SMBUS_I2C_BLOCK_MAX) - if (i2c_smbus_read_i2c_block_data(client, - i, data->data + i) - != I2C_SMBUS_I2C_BLOCK_MAX) { - printk(KERN_WARNING "eeprom.o: block read fail at 0x%.2x!\n", i); - goto DONE; - } - } else { - if (i2c_smbus_write_byte(client, slice << 5)) { - printk(KERN_WARNING "eeprom.o: read start fail at 0x%.2x!\n", slice << 5); - goto DONE; - } - for (i = slice << 5; i < (slice + 1) << 5; i++) { - j = i2c_smbus_read_byte(client); - if (j < 0) { - printk(KERN_WARNING "eeprom.o: read fail at 0x%.2x!\n", i); - goto DONE; - } - data->data[i] = (u8) j; - } - } - data->last_updated[slice] = jiffies; - data->valid |= (1 << slice); - } -DONE: - up(&data->update_lock); -} - - -void eeprom_contents(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - int i; - int nr = ctl_name - EEPROM_SYSCTL1; - struct eeprom_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - eeprom_update_client(client, nr >> 1); - /* Hide Vaio security settings to regular users */ - if (nr == 0 && data->nature == NATURE_VAIO - && !capable(CAP_SYS_ADMIN)) - for (i = 0; i < 16; i++) - results[i] = 0; - else - for (i = 0; i < 16; i++) - results[i] = data->data[i + nr * 16]; -#ifdef DEBUG - printk(KERN_DEBUG "eeprom.o: 0x%X EEPROM contents (row %d):", - client->addr, nr + 1); - if (nr == 0 && data->nature == NATURE_VAIO) - printk(" \n"); - else { - for (i = 0; i < 16; i++) - printk(" 0x%02X", data->data[i + nr * 16]); - printk("\n"); - } -#endif - *nrels_mag = 16; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - -/* No writes to the EEPROM (yet, anyway) (PAE) */ - printk("eeprom.o: No writes to EEPROMs supported!\n"); - } -} - -static int __init sm_eeprom_init(void) -{ - printk("eeprom.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&eeprom_driver); -} - -static void __exit sm_eeprom_exit(void) -{ - i2c_del_driver(&eeprom_driver); -} - - - -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("EEPROM driver"); - -module_init(sm_eeprom_init); -module_exit(sm_eeprom_exit); diff --git a/kernel/chips/f71805f.c b/kernel/chips/f71805f.c deleted file mode 100644 index 39f8694c..00000000 --- a/kernel/chips/f71805f.c +++ /dev/null @@ -1,757 +0,0 @@ -/* - * f71805f.c - driver for the Fintek F71805F Super-I/O chip integrated - * hardware monitoring features - * Copyright (C) 2005 Jean Delvare - * - * The F71805F is a LPC Super-I/O chip made by Fintek. It integrates - * complete hardware monitoring features: voltage, fan and temperature - * sensors, and manual and automatic fan speed control. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" - -/* ISA address is read from Super-I/O configuration space */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -SENSORS_INSMOD_1(f71805f); - -#define DRVNAME "f71805f" - -/* - * Super-I/O constants and functions - */ - -#define F71805F_LD_HWM 0x04 - -#define SIO_REG_LDSEL 0x07 /* Logical device select */ -#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ -#define SIO_REG_DEVREV 0x22 /* Device revision */ -#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */ -#define SIO_REG_ENABLE 0x30 /* Logical device enable */ -#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ - -#define SIO_FINTEK_ID 0x1934 -#define SIO_F71805F_ID 0x0406 - -static inline int -superio_inb(int base, int reg) -{ - outb(reg, base); - return inb(base + 1); -} - -static int -superio_inw(int base, int reg) -{ - int val; - outb(reg++, base); - val = inb(base + 1) << 8; - outb(reg, base); - val |= inb(base + 1); - return val; -} - -static inline void -superio_select(int base, int ld) -{ - outb(SIO_REG_LDSEL, base); - outb(ld, base + 1); -} - -static inline void -superio_enter(int base) -{ - outb(0x87, base); - outb(0x87, base); -} - -static inline void -superio_exit(int base) -{ - outb(0xaa, base); -} - -/* - * ISA constants - */ - -#define REGION_LENGTH 8 -#define ADDR_REG_OFFSET 5 -#define DATA_REG_OFFSET 6 - -/* - * Registers - */ - -/* in nr from 0 to 8 (8-bit values) */ -#define F71805F_REG_IN(nr) (0x10 + (nr)) -#define F71805F_REG_IN_HIGH(nr) (0x40 + 2 * (nr)) -#define F71805F_REG_IN_LOW(nr) (0x41 + 2 * (nr)) -/* fan nr from 0 to 2 (12-bit values, two registers) */ -#define F71805F_REG_FAN(nr) (0x20 + 2 * (nr)) -#define F71805F_REG_FAN_LOW(nr) (0x28 + 2 * (nr)) -#define F71805F_REG_FAN_CTRL(nr) (0x60 + 16 * (nr)) -/* temp nr from 0 to 2 (8-bit values) */ -#define F71805F_REG_TEMP(nr) (0x1B + (nr)) -#define F71805F_REG_TEMP_HIGH(nr) (0x54 + 2 * (nr)) -#define F71805F_REG_TEMP_HYST(nr) (0x55 + 2 * (nr)) -#define F71805F_REG_TEMP_MODE 0x01 - -#define F71805F_REG_START 0x00 -/* status nr from 0 to 2 */ -#define F71805F_REG_STATUS(nr) (0x36 + (nr)) - -/* - * Data structures and manipulation thereof - */ - -struct f71805f_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - unsigned long last_limits; /* In jiffies */ - - /* Register values */ - u8 in[9]; - u8 in_high[9]; - u8 in_low[9]; - u16 fan[3]; - u16 fan_low[3]; - u8 fan_enabled; /* Read once at init time */ - u8 temp[3]; - u8 temp_high[3]; - u8 temp_hyst[3]; - u8 temp_mode; - u8 alarms[3]; -}; - -static inline long in_from_reg(u8 reg) -{ - return (reg * 8); -} - -/* The 2 least significant bits are not used */ -static inline u8 in_to_reg(long val) -{ - if (val <= 0) - return 0; - if (val >= 2016) - return 0xfc; - return (((val + 16) / 32) << 2); -} - -/* in0 is downscaled by a factor 2 internally */ -static inline long in0_from_reg(u8 reg) -{ - return (reg * 16); -} - -static inline u8 in0_to_reg(long val) -{ - if (val <= 0) - return 0; - if (val >= 4032) - return 0xfc; - return (((val + 32) / 64) << 2); -} - -/* The 4 most significant bits are not used */ -static inline long fan_from_reg(u16 reg) -{ - reg &= 0xfff; - if (!reg || reg == 0xfff) - return 0; - return (1500000 / reg); -} - -static inline u16 fan_to_reg(long rpm) -{ - /* If the low limit is set below what the chip can measure, - store the largest possible 12-bit value in the registers, - so that no alarm will ever trigger. */ - if (rpm < 367) - return 0xfff; - return (1500000 / rpm); -} - -static inline u8 temp_to_reg(long val) -{ - if (val < 0) - val = 0; - else if (val > 0xff) - val = 0xff; - return val; -} - -/* - * Driver and client management - */ - -static u8 f71805f_read8(struct i2c_client *client, u8 reg) -{ - struct f71805f_data *data = client->data; - u8 val; - - down(&data->lock); - outb_p(reg, client->addr + ADDR_REG_OFFSET); - val = inb_p(client->addr + DATA_REG_OFFSET); - up(&data->lock); - - return val; -} - -static void f71805f_write8(struct i2c_client *client, u8 reg, u8 val) -{ - struct f71805f_data *data = client->data; - - down(&data->lock); - outb_p(reg, client->addr + ADDR_REG_OFFSET); - outb_p(val, client->addr + DATA_REG_OFFSET); - up(&data->lock); -} - -/* It is important to read the MSB first, because doing so latches the - value of the LSB, so we are sure both bytes belong to the same value. */ -static u16 f71805f_read16(struct i2c_client *client, u8 reg) -{ - struct f71805f_data *data = client->data; - u16 val; - - down(&data->lock); - outb_p(reg, client->addr + ADDR_REG_OFFSET); - val = inb_p(client->addr + DATA_REG_OFFSET) << 8; - outb_p(++reg, client->addr + ADDR_REG_OFFSET); - val |= inb_p(client->addr + DATA_REG_OFFSET); - up(&data->lock); - - return val; -} - -static void f71805f_write16(struct i2c_client *client, u8 reg, u16 val) -{ - struct f71805f_data *data = client->data; - - down(&data->lock); - outb_p(reg, client->addr + ADDR_REG_OFFSET); - outb_p(val >> 8, client->addr + DATA_REG_OFFSET); - outb_p(++reg, client->addr + ADDR_REG_OFFSET); - outb_p(val & 0xff, client->addr + DATA_REG_OFFSET); - up(&data->lock); -} - -static struct i2c_driver f71805f_driver; -static ctl_table f71805f_dir_table_template[]; - -static void f71805f_init_client(struct i2c_client *client) -{ - struct f71805f_data *data = client->data; - u8 reg; - int i; - - reg = f71805f_read8(client, F71805F_REG_START); - if ((reg & 0x41) != 0x01) { - printk(KERN_DEBUG DRVNAME ": Starting monitoring " - "operations\n"); - f71805f_write8(client, - F71805F_REG_START, (reg | 0x01) & ~0x40); - } - - /* Fan monitoring can be disabled. If it is, we won't be polling - the register values, and instead set the cache to return 0 RPM. */ - for (i = 0; i < 3; i++) { - reg = f71805f_read8(client, F71805F_REG_FAN_CTRL(i)); - if (!(reg & 0x80)) - data->fan_enabled |= (1 << i); - else - data->fan[i] = data->fan_low[i] = 0xfff; - } -} - -static int f71805f_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - struct i2c_client *client; - struct f71805f_data *data; - int err; - - if (!request_region(address, REGION_LENGTH, f71805f_driver.name)) { - err = -EBUSY; - goto exit; - } - - if (!(data = kmalloc(sizeof(struct f71805f_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit_release; - } - memset(data, 0, sizeof(struct f71805f_data)); - - /* Fill in the client fields */ - client = &data->client; - client->addr = address; - client->data = data; - client->adapter = adapter; - client->driver = &f71805f_driver; - strcpy(client->name, "F71805F chip"); - - init_MUTEX(&data->lock); - init_MUTEX(&data->update_lock); - - /* Tell the i2c core a new client has arrived */ - if ((err = i2c_attach_client(client))) - goto exit_free; - - /* Initialize the F71805F chip */ - f71805f_init_client(client); - - /* Register a new directory entry in /proc */ - err = i2c_register_entry(client, "f71805f", - f71805f_dir_table_template, THIS_MODULE); - if (err < 0) - goto exit_detach; - data->sysctl_id = err; - - return 0; - -exit_detach: - i2c_detach_client(client); -exit_free: - kfree(data); -exit_release: - release_region(address, REGION_LENGTH); -exit: - return err; -} - -static int f71805f_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, f71805f_detect); -} - -static int f71805f_detach_client(struct i2c_client *client) -{ - int err; - struct f71805f_data *data = client->data; - - i2c_deregister_entry(data->sysctl_id); - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR DRVNAME ": Client deregistration failed, " - "client not detached\n"); - return err; - } - - release_region(client->addr, REGION_LENGTH); - kfree(client->data); - - return 0; -} - -static void f71805f_update_client(struct i2c_client *client) -{ - struct f71805f_data *data = client->data; - int nr; - - down(&data->update_lock); - - /* Limit registers cache is refreshed after 60 seconds */ - if ((jiffies - data->last_limits > 60 * HZ) - || (jiffies < data->last_limits) - || !data->valid) { - for (nr = 0; nr < 9; nr++) { - data->in_high[nr] = f71805f_read8(client, - F71805F_REG_IN_HIGH(nr)); - data->in_low[nr] = f71805f_read8(client, - F71805F_REG_IN_LOW(nr)); - } - for (nr = 0; nr < 3; nr++) { - if (data->fan_enabled & (1 << nr)) - data->fan_low[nr] = f71805f_read16(client, - F71805F_REG_FAN_LOW(nr)); - } - for (nr = 0; nr < 3; nr++) { - data->temp_high[nr] = f71805f_read8(client, - F71805F_REG_TEMP_HIGH(nr)); - data->temp_hyst[nr] = f71805f_read8(client, - F71805F_REG_TEMP_HYST(nr)); - } - data->temp_mode = f71805f_read8(client, F71805F_REG_TEMP_MODE); - - data->last_limits = jiffies; - } - - /* Measurement registers cache is refreshed after 1 second */ - if ((jiffies - data->last_updated > HZ) - || (jiffies < data->last_updated) - || !data->valid) { - for (nr = 0; nr < 9; nr++) { - data->in[nr] = f71805f_read8(client, - F71805F_REG_IN(nr)); - } - for (nr = 0; nr < 3; nr++) { - if (data->fan_enabled & (1 << nr)) - data->fan[nr] = f71805f_read16(client, - F71805F_REG_FAN(nr)); - } - for (nr = 0; nr < 3; nr++) { - data->temp[nr] = f71805f_read8(client, - F71805F_REG_TEMP(nr)); - } - for (nr = 0; nr < 3; nr++) { - data->alarms[nr] = f71805f_read8(client, - F71805F_REG_STATUS(nr)); - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -/* -- SENSORS SYSCTL START -- */ -#define F71805F_SYSCTL_IN0 1000 -#define F71805F_SYSCTL_IN1 1001 -#define F71805F_SYSCTL_IN2 1002 -#define F71805F_SYSCTL_IN3 1003 -#define F71805F_SYSCTL_IN4 1004 -#define F71805F_SYSCTL_IN5 1005 -#define F71805F_SYSCTL_IN6 1006 -#define F71805F_SYSCTL_IN7 1007 -#define F71805F_SYSCTL_IN8 1008 -#define F71805F_SYSCTL_FAN1 1101 -#define F71805F_SYSCTL_FAN2 1102 -#define F71805F_SYSCTL_FAN3 1103 -#define F71805F_SYSCTL_TEMP1 1201 -#define F71805F_SYSCTL_TEMP2 1202 -#define F71805F_SYSCTL_TEMP3 1203 -#define F71805F_SYSCTL_SENSOR1 1211 -#define F71805F_SYSCTL_SENSOR2 1212 -#define F71805F_SYSCTL_SENSOR3 1213 -#define F71805F_SYSCTL_ALARMS_IN 1090 -#define F71805F_SYSCTL_ALARMS_FAN 1190 -#define F71805F_SYSCTL_ALARMS_TEMP 1290 -/* -- SENSORS SYSCTL END -- */ - -static void f71805f_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct f71805f_data *data = client->data; - int nr = ctl_name - F71805F_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - f71805f_update_client(client); - results[0] = in_from_reg(data->in_low[nr]); - results[1] = in_from_reg(data->in_high[nr]); - results[2] = in_from_reg(data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag < 1) - return; - - down(&data->update_lock); - data->in_low[nr] = in_to_reg(results[0]); - f71805f_write8(client, F71805F_REG_IN_LOW(nr), - data->in_low[nr]); - - if (*nrels_mag >= 2) { - data->in_high[nr] = in_to_reg(results[1]); - f71805f_write8(client, F71805F_REG_IN_HIGH(nr), - data->in_high[nr]); - } - up(&data->update_lock); - } -} - -static void f71805f_in0(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct f71805f_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - f71805f_update_client(client); - results[0] = in0_from_reg(data->in_low[0]); - results[1] = in0_from_reg(data->in_high[0]); - results[2] = in0_from_reg(data->in[0]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag < 1) - return; - - down(&data->update_lock); - data->in_low[0] = in0_to_reg(results[0]); - f71805f_write8(client, F71805F_REG_IN_LOW(0), - data->in_low[0]); - - if (*nrels_mag >= 2) { - data->in_high[0] = in0_to_reg(results[1]); - f71805f_write8(client, F71805F_REG_IN_HIGH(0), - data->in_high[0]); - } - up(&data->update_lock); - } -} - -static void f71805f_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct f71805f_data *data = client->data; - int nr = ctl_name - F71805F_SYSCTL_FAN1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - f71805f_update_client(client); - results[0] = fan_from_reg(data->fan_low[nr]); - results[1] = fan_from_reg(data->fan[nr]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag < 1) - return; - - down(&data->update_lock); - data->fan_low[nr] = fan_to_reg(results[0]); - f71805f_write16(client, F71805F_REG_FAN_LOW(nr), - data->fan_low[nr]); - up(&data->update_lock); - } -} - -static void f71805f_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct f71805f_data *data = client->data; - int nr = ctl_name - F71805F_SYSCTL_TEMP1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - f71805f_update_client(client); - results[0] = data->temp_high[nr]; - results[1] = data->temp_hyst[nr]; - results[2] = data->temp[nr]; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag < 1) - return; - - down(&data->update_lock); - data->temp_high[nr] = temp_to_reg(results[0]); - f71805f_write8(client, F71805F_REG_TEMP_HIGH(nr), - data->temp_high[nr]); - - if (*nrels_mag >= 2) { - data->temp_hyst[nr] = temp_to_reg(results[1]); - f71805f_write8(client, F71805F_REG_TEMP_HYST(nr), - data->temp_hyst[nr]); - } - up(&data->update_lock); - } -} - -static void f71805f_sensor(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct f71805f_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - int nr = ctl_name - F71805F_SYSCTL_SENSOR1; - - f71805f_update_client(client); - results[0] = (data->temp_mode & (1 << nr)) ? 3 : 4; - *nrels_mag = 1; - } -} - -static void f71805f_alarms_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct f71805f_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - f71805f_update_client(client); - results[0] = data->alarms[0] - | ((data->alarms[1] & 0x01) << 8); - *nrels_mag = 1; - } -} - -static void f71805f_alarms_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct f71805f_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - f71805f_update_client(client); - results[0] = data->alarms[2] & 0x07; - *nrels_mag = 1; - } -} - -static void f71805f_alarms_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct f71805f_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - f71805f_update_client(client); - results[0] = (data->alarms[1] >> 3) & 0x07; - *nrels_mag = 1; - } -} - -static ctl_table f71805f_dir_table_template[] = { - { F71805F_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in0 }, - { F71805F_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, - { F71805F_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, - { F71805F_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, - { F71805F_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, - { F71805F_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, - { F71805F_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, - { F71805F_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, - { F71805F_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_in }, - { F71805F_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_fan }, - { F71805F_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_fan }, - { F71805F_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_fan }, - { F71805F_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_temp }, - { F71805F_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_temp }, - { F71805F_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_temp }, - { F71805F_SYSCTL_SENSOR1, "sensor1", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_sensor }, - { F71805F_SYSCTL_SENSOR2, "sensor2", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_sensor }, - { F71805F_SYSCTL_SENSOR3, "sensor3", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_sensor }, - { F71805F_SYSCTL_ALARMS_IN, "alarms_in", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_alarms_in }, - { F71805F_SYSCTL_ALARMS_FAN, "alarms_fan", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_alarms_fan }, - { F71805F_SYSCTL_ALARMS_TEMP, "alarms_temp", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &f71805f_alarms_temp }, - { 0 } -}; - -static struct i2c_driver f71805f_driver = { - .name = "F71805F sensor driver", - .flags = I2C_DF_NOTIFY, - .attach_adapter = f71805f_attach_adapter, - .detach_client = f71805f_detach_client, -}; - -static int __init f71805f_find(int sioaddr, unsigned int *address) -{ - int err = -ENODEV; - u16 devid; - - superio_enter(sioaddr); - - devid = superio_inw(sioaddr, SIO_REG_MANID); - if (devid != SIO_FINTEK_ID) - goto exit; - - devid = superio_inw(sioaddr, SIO_REG_DEVID); - if (devid != SIO_F71805F_ID) { - printk(KERN_INFO DRVNAME ": Unsupported Fintek device, " - "skipping\n"); - goto exit; - } - - superio_select(sioaddr, F71805F_LD_HWM); - if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) { - printk(KERN_WARNING DRVNAME ": Device not activated, " - "skipping\n"); - goto exit; - } - - *address = superio_inw(sioaddr, SIO_REG_ADDR); - if (*address == 0) { - printk(KERN_WARNING DRVNAME ": Base address not set, " - "skipping\n"); - goto exit; - } - *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */ - - err = 0; - printk(KERN_INFO DRVNAME ": Found F71805F chip at %#x, revision %u\n", - *address, superio_inb(sioaddr, SIO_REG_DEVREV)); - -exit: - superio_exit(sioaddr); - return err; -} - -static int __init f71805f_init(void) -{ - printk("%s: Driver version %s (%s)\n", DRVNAME, LM_VERSION, LM_DATE); - - if (f71805f_find(0x2e, &normal_isa[0]) - && f71805f_find(0x4e, &normal_isa[0])) - return -ENODEV; - - return i2c_add_driver(&f71805f_driver); -} - -static void __exit f71805f_exit(void) -{ - i2c_del_driver(&f71805f_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("F71805F hardware monitoring driver"); - -module_init(f71805f_init); -module_exit(f71805f_exit); diff --git a/kernel/chips/fscher.c b/kernel/chips/fscher.c deleted file mode 100644 index 8fd77ada..00000000 --- a/kernel/chips/fscher.c +++ /dev/null @@ -1,729 +0,0 @@ -/* - fscher.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (C) 2003, 2004 Reinhard Nissl - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - fujitsu siemens hermes chip, - module based on fscpos.c - Copyright (C) 2000 Hermann Jung - Copyright (C) 1998, 1999 Frodo Looijaard - and Philip Edelbrock -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -#ifndef I2C_DRIVERID_FSCHER -#define I2C_DRIVERID_FSCHER 1046 -#endif - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x73, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(fscher); - -/* The FSCHER registers */ - -/* chip identification */ -#define FSCHER_REG_IDENT_0 0x00 -#define FSCHER_REG_IDENT_1 0x01 -#define FSCHER_REG_IDENT_2 0x02 -#define FSCHER_REG_REVISION 0x03 - -/* global control and status */ -#define FSCHER_REG_EVENT_STATE 0x04 -#define FSCHER_REG_CONTROL 0x05 - -/* watchdog */ -#define FSCHER_REG_WDOG_PRESET 0x28 -#define FSCHER_REG_WDOG_STATE 0x23 -#define FSCHER_REG_WDOG_CONTROL 0x21 - -/* fan 0 */ -#define FSCHER_REG_FAN0_MIN 0x55 -#define FSCHER_REG_FAN0_ACT 0x0e -#define FSCHER_REG_FAN0_STATE 0x0d -#define FSCHER_REG_FAN0_RIPPLE 0x0f - -/* fan 1 */ -#define FSCHER_REG_FAN1_MIN 0x65 -#define FSCHER_REG_FAN1_ACT 0x6b -#define FSCHER_REG_FAN1_STATE 0x62 -#define FSCHER_REG_FAN1_RIPPLE 0x6f - -/* fan 2 */ -#define FSCHER_REG_FAN2_MIN 0xb5 -#define FSCHER_REG_FAN2_ACT 0xbb -#define FSCHER_REG_FAN2_STATE 0xb2 -#define FSCHER_REG_FAN2_RIPPLE 0xbf - -/* voltage supervision */ -#define FSCHER_REG_VOLT_12 0x45 -#define FSCHER_REG_VOLT_5 0x42 -#define FSCHER_REG_VOLT_BATT 0x48 - -/* temperatures */ -/* sensor 0 */ -#define FSCHER_REG_TEMP0_ACT 0x64 -#define FSCHER_REG_TEMP0_STATE 0x71 - -/* sensor 1 */ -#define FSCHER_REG_TEMP1_ACT 0x32 -#define FSCHER_REG_TEMP1_STATE 0x81 - -/* sensor 2 */ -#define FSCHER_REG_TEMP2_ACT 0x35 -#define FSCHER_REG_TEMP2_STATE 0x91 - - - -/* Initial limits */ - -/* For each registered FSCHER, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new fscher client is - allocated. */ -struct fscher_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 revision; /* revision of chip */ - u8 global_event; /* global event status */ - u8 global_control; /* global control register */ - u8 watchdog[3]; /* watchdog */ - u8 volt[3]; /* 12, 5, battery current */ - u8 temp_act[3]; /* temperature */ - u8 temp_status[3]; /* status of sensor */ - u8 fan_act[3]; /* fans revolutions per second */ - u8 fan_status[3]; /* fan status */ - u8 fan_min[3]; /* fan min value for rps */ - u8 fan_ripple[3]; /* divider for rps */ -}; - - -static int fscher_attach_adapter(struct i2c_adapter *adapter); -static int fscher_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int fscher_detach_client(struct i2c_client *client); - -static int fscher_read_value(struct i2c_client *client, u8 register); -static int fscher_write_value(struct i2c_client *client, u8 register, - u8 value); -static void fscher_update_client(struct i2c_client *client); -static void fscher_init_client(struct i2c_client *client); - - -static void fscher_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void fscher_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscher_pwm_internal(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results, - int nr, int reg_min); -static void fscher_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscher_fan_internal(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results, - int nr, int reg_state, int res_ripple); -static void fscher_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscher_volt(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscher_wdog(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver fscher_driver = { - .name = "FSCHER sensor driver", - .id = I2C_DRIVERID_FSCHER, - .flags = I2C_DF_NOTIFY, - .attach_adapter = fscher_attach_adapter, - .detach_client = fscher_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define FSCHER_SYSCTL_VOLT0 1000 /* 12 volt supply */ -#define FSCHER_SYSCTL_VOLT1 1001 /* 5 volt supply */ -#define FSCHER_SYSCTL_VOLT2 1002 /* batterie voltage */ -#define FSCHER_SYSCTL_FAN0 1101 /* state, ripple, actual value - fan 0 */ -#define FSCHER_SYSCTL_FAN1 1102 /* state, ripple, actual value - fan 1 */ -#define FSCHER_SYSCTL_FAN2 1103 /* state, ripple, actual value - fan 2 */ -#define FSCHER_SYSCTL_TEMP0 1201 /* state and value of sensor 0, - cpu die */ -#define FSCHER_SYSCTL_TEMP1 1202 /* state and value of sensor 1, - motherboard */ -#define FSCHER_SYSCTL_TEMP2 1203 /* state and value of sensor 2, - chassis */ -#define FSCHER_SYSCTL_PWM0 1301 /* min fan 0 */ -#define FSCHER_SYSCTL_PWM1 1302 /* min fan 1 */ -#define FSCHER_SYSCTL_PWM2 1303 /* min fan 2 */ -#define FSCHER_SYSCTL_REV 2000 /* revision */ -#define FSCHER_SYSCTL_EVENT 2001 /* global event status */ -#define FSCHER_SYSCTL_CONTROL 2002 /* global control byte */ -#define FSCHER_SYSCTL_WDOG 2003 /* watch dog preset, state and - control */ -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected FSCHER. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table fscher_dir_table_template[] = { - {FSCHER_SYSCTL_REV, "rev", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_in}, - {FSCHER_SYSCTL_EVENT, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_in}, - {FSCHER_SYSCTL_CONTROL, "control", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_in}, - {FSCHER_SYSCTL_TEMP0, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_temp}, - {FSCHER_SYSCTL_TEMP1, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_temp}, - {FSCHER_SYSCTL_TEMP2, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_temp}, - {FSCHER_SYSCTL_VOLT0, "in0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_volt}, - {FSCHER_SYSCTL_VOLT1, "in1", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_volt}, - {FSCHER_SYSCTL_VOLT2, "in2", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_volt}, - {FSCHER_SYSCTL_FAN0, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_fan}, - {FSCHER_SYSCTL_FAN1, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_fan}, - {FSCHER_SYSCTL_FAN2, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_fan}, - {FSCHER_SYSCTL_PWM0, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_pwm}, - {FSCHER_SYSCTL_PWM1, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_pwm}, - {FSCHER_SYSCTL_PWM2, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_pwm}, - {FSCHER_SYSCTL_WDOG, "wdog", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscher_wdog}, - {0} -}; - -static int fscher_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, fscher_detect); -} - -int fscher_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct fscher_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety - check at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk("fscher.o: fscher_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access fscher_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct fscher_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &fscher_driver; - new_client->flags = 0; - - /* Do the remaining detection unless force or force_fscher parameter */ - if (kind < 0) { - if (fscher_read_value(new_client, FSCHER_REG_IDENT_0) != 0x48) /* 'H' */ - goto ERROR1; - if (fscher_read_value(new_client, FSCHER_REG_IDENT_1) != 0x45) /* 'E' */ - goto ERROR1; - if (fscher_read_value(new_client, FSCHER_REG_IDENT_2) != 0x52) /* 'R' */ - goto ERROR1; - } - - kind = fscher; - - type_name = "fscher"; - client_name = "fsc hermes chip"; - - /* Fill in the remaining client fields and put it into the - global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - fscher_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - fscher_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int fscher_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct fscher_data *) (client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("fscher.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -static int fscher_read_value(struct i2c_client *client, u8 reg) -{ -#ifdef DEBUG - printk("fscher: read reg 0x%02x\n",reg); -#endif - return i2c_smbus_read_byte_data(client, reg); -} - -static int fscher_write_value(struct i2c_client *client, u8 reg, u8 value) -{ -#ifdef DEBUG - printk("fscher: write reg 0x%02x, val 0x%02x\n",reg, value); -#endif - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new FSCHER. */ -static void fscher_init_client(struct i2c_client *client) -{ - struct fscher_data *data = client->data; - - /* read revision from chip */ - data->revision = fscher_read_value(client,FSCHER_REG_REVISION); -} - -static void fscher_update_client(struct i2c_client *client) -{ - struct fscher_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 2 * HZ) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting fscher update\n"); -#endif - data->temp_act[0] = fscher_read_value(client, FSCHER_REG_TEMP0_ACT); - data->temp_act[1] = fscher_read_value(client, FSCHER_REG_TEMP1_ACT); - data->temp_act[2] = fscher_read_value(client, FSCHER_REG_TEMP2_ACT); - data->temp_status[0] = fscher_read_value(client, FSCHER_REG_TEMP0_STATE); - data->temp_status[1] = fscher_read_value(client, FSCHER_REG_TEMP1_STATE); - data->temp_status[2] = fscher_read_value(client, FSCHER_REG_TEMP2_STATE); - - data->volt[0] = fscher_read_value(client, FSCHER_REG_VOLT_12); - data->volt[1] = fscher_read_value(client, FSCHER_REG_VOLT_5); - data->volt[2] = fscher_read_value(client, FSCHER_REG_VOLT_BATT); - - data->fan_act[0] = fscher_read_value(client, FSCHER_REG_FAN0_ACT); - data->fan_act[1] = fscher_read_value(client, FSCHER_REG_FAN1_ACT); - data->fan_act[2] = fscher_read_value(client, FSCHER_REG_FAN2_ACT); - data->fan_status[0] = fscher_read_value(client, FSCHER_REG_FAN0_STATE); - data->fan_status[1] = fscher_read_value(client, FSCHER_REG_FAN1_STATE); - data->fan_status[2] = fscher_read_value(client, FSCHER_REG_FAN2_STATE); - data->fan_min[0] = fscher_read_value(client, FSCHER_REG_FAN0_MIN); - data->fan_min[1] = fscher_read_value(client, FSCHER_REG_FAN1_MIN); - data->fan_min[2] = fscher_read_value(client, FSCHER_REG_FAN2_MIN); - data->fan_ripple[0] = fscher_read_value(client, FSCHER_REG_FAN0_RIPPLE); - data->fan_ripple[1] = fscher_read_value(client, FSCHER_REG_FAN1_RIPPLE); - data->fan_ripple[2] = fscher_read_value(client, FSCHER_REG_FAN2_RIPPLE); - - data->watchdog[0] = fscher_read_value(client, FSCHER_REG_WDOG_PRESET); - data->watchdog[1] = fscher_read_value(client, FSCHER_REG_WDOG_STATE); - data->watchdog[2] = fscher_read_value(client, FSCHER_REG_WDOG_CONTROL); - - data->global_event = fscher_read_value(client, FSCHER_REG_EVENT_STATE); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void fscher_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscher_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscher_update_client(client); - switch(ctl_name) { - case FSCHER_SYSCTL_REV: - results[0] = data->revision ; - break; - case FSCHER_SYSCTL_EVENT: - /* bits 6, 5 and 2 are reserved => mask with 0x9b */ - results[0] = data->global_event & 0x9b; - break; - case FSCHER_SYSCTL_CONTROL: - results[0] = data->global_control & 0x01; - break; - default: - printk("fscher: ctl_name %d not supported\n", ctl_name); - *nrels_mag = 0; - return; - } - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if((ctl_name == FSCHER_SYSCTL_CONTROL) && (*nrels_mag >= 1)) { - data->global_control = (results[0] & 0x01); - printk("fscher: writing 0x%02x to global_control\n", - data->global_control); - fscher_write_value(client,FSCHER_REG_CONTROL, - data->global_control); - } - else - printk("fscher: writing to chip not supported\n"); - } -} - - -#define TEMP_FROM_REG(val) (val-128) - -void fscher_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscher_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscher_update_client(client); - switch(ctl_name) { - case FSCHER_SYSCTL_TEMP0: - results[0] = data->temp_status[0] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[0]); - break; - case FSCHER_SYSCTL_TEMP1: - results[0] = data->temp_status[1] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[1]); - break; - case FSCHER_SYSCTL_TEMP2: - results[0] = data->temp_status[2] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[2]); - break; - default: - printk("fscher: ctl_name %d not supported\n", ctl_name); - *nrels_mag = 0; - return; - } - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if(*nrels_mag >= 1) { - switch(ctl_name) { - case FSCHER_SYSCTL_TEMP0: - data->temp_status[0] = (data->temp_status[0] & ~0x02) - | (results[0] & 0x02); - printk("fscher: writing value 0x%02x to temp0_status\n", - data->temp_status[0]); - fscher_write_value(client, FSCHER_REG_TEMP0_STATE, - data->temp_status[0] & 0x02); - break; - case FSCHER_SYSCTL_TEMP1: - data->temp_status[1] = (data->temp_status[1] & ~0x02) - | (results[0] & 0x02); - printk("fscher: writing value 0x%02x to temp1_status\n", - data->temp_status[1]); - fscher_write_value(client, FSCHER_REG_TEMP1_STATE, - data->temp_status[1] & 0x02); - break; - case FSCHER_SYSCTL_TEMP2: - data->temp_status[2] = (data->temp_status[2] & ~0x02) - | (results[0] & 0x02); - printk("fscher: writing value 0x%02x to temp2_status\n", - data->temp_status[2]); - fscher_write_value(client, FSCHER_REG_TEMP2_STATE, - data->temp_status[2] & 0x02); - break; - default: - printk("fscher: ctl_name %d not supported\n",ctl_name); - } - } - else - printk("fscher: writing to chip not supported\n"); - } -} - -/* - * The final conversion is specified in sensors.conf, as it depends on - * mainboard specific values. We export the registers contents as - * pseudo-hundredths-of-Volts (range 0V - 2.55V). Not that it makes much - * sense per se, but it minimizes the conversions count and keeps the - * values within a usual range. - */ -void fscher_volt(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscher_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - fscher_update_client(client); - switch(ctl_name) { - case FSCHER_SYSCTL_VOLT0: - results[0] = data->volt[0]; - break; - case FSCHER_SYSCTL_VOLT1: - results[0] = data->volt[1]; - break; - case FSCHER_SYSCTL_VOLT2: - results[0] = data->volt[2]; - break; - default: - printk("fscher: ctl_name %d not supported\n", ctl_name); - *nrels_mag = 0; - return; - } - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - printk("fscher: writing to chip not supported\n"); - } -} - -void fscher_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - - switch(ctl_name) { - case FSCHER_SYSCTL_PWM0: - fscher_pwm_internal(client,operation,ctl_name,nrels_mag,results, - 0,FSCHER_REG_FAN0_MIN); - break; - case FSCHER_SYSCTL_PWM1: - fscher_pwm_internal(client,operation,ctl_name,nrels_mag,results, - 1,FSCHER_REG_FAN1_MIN); - break; - case FSCHER_SYSCTL_PWM2: - fscher_pwm_internal(client,operation,ctl_name,nrels_mag,results, - 2,FSCHER_REG_FAN2_MIN); - break; - default: - printk("fscher: illegal pwm nr %d\n",ctl_name); - } -} - -void fscher_pwm_internal(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results, - int nr, int reg_min) -{ - struct fscher_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscher_update_client(client); - results[0] = data->fan_min[nr]; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if(*nrels_mag >= 1) { - data->fan_min[nr] = results[0]; - printk("fscher: writing value 0x%02x to fan%d_min\n", - data->fan_min[nr],nr); - fscher_write_value(client,reg_min,data->fan_min[nr]); - } - } -} - -void fscher_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - switch(ctl_name) { - case FSCHER_SYSCTL_FAN0: - fscher_fan_internal(client,operation,ctl_name,nrels_mag,results, - 0,FSCHER_REG_FAN0_STATE, FSCHER_REG_FAN0_RIPPLE); - break; - case FSCHER_SYSCTL_FAN1: - fscher_fan_internal(client,operation,ctl_name,nrels_mag,results, - 1,FSCHER_REG_FAN1_STATE, FSCHER_REG_FAN1_RIPPLE); - break; - case FSCHER_SYSCTL_FAN2: - fscher_fan_internal(client,operation,ctl_name,nrels_mag,results, - 2,FSCHER_REG_FAN2_STATE, FSCHER_REG_FAN2_RIPPLE); - break; - default: - printk("fscher: illegal fan nr %d\n",ctl_name); - } -} - -#define RPM_FROM_REG(val) (val*60) - -void fscher_fan_internal(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results, - int nr, int reg_state, int reg_ripple) -{ - struct fscher_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscher_update_client(client); - results[0] = data->fan_status[nr] & 0x04; - results[1] = data->fan_ripple[nr] & 0x03; - results[2] = RPM_FROM_REG(data->fan_act[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if(*nrels_mag >= 1) { - data->fan_status[nr] = results[0] & 0x04; - printk("fscher: writing value 0x%02x to fan%d_status\n", - data->fan_status[nr],nr); - fscher_write_value(client,reg_state,data->fan_status[nr]); - } - if(*nrels_mag >= 2) { - if((results[1] & 0x03) == 0) { - printk("fscher: fan%d ripple 0 not allowed\n",nr); - return; - } - data->fan_ripple[nr] = results[1] & 0x03; - printk("fscher: writing value 0x%02x to fan%d_ripple\n", - data->fan_ripple[nr],nr); - fscher_write_value(client,reg_ripple,data->fan_ripple[nr]); - } - } -} - -void fscher_wdog(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscher_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscher_update_client(client); - results[0] = data->watchdog[0] ; - results[1] = data->watchdog[1] & 0x02; - results[2] = data->watchdog[2] & 0xd0; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->watchdog[0] = results[0] & 0xff; - printk("fscher: writing value 0x%02x to wdog_preset\n", - data->watchdog[0]); - fscher_write_value(client,FSCHER_REG_WDOG_PRESET,data->watchdog[0]); - } - if (*nrels_mag >= 2) { - data->watchdog[1] = results[1] & 0x02; - printk("fscher: writing value 0x%02x to wdog_state\n", - data->watchdog[1]); - fscher_write_value(client,FSCHER_REG_WDOG_STATE,data->watchdog[1]); - } - if (*nrels_mag >= 3) { - data->watchdog[2] = results[2] & 0xf0; - printk("fscher: writing value 0x%02x to wdog_control\n", - data->watchdog[2]); - fscher_write_value(client,FSCHER_REG_WDOG_CONTROL,data->watchdog[2]); - } - } -} - -static int __init sm_fscher_init(void) -{ - printk("fscher.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&fscher_driver); -} - -static void __exit sm_fscher_exit(void) -{ - i2c_del_driver(&fscher_driver); -} - - - -MODULE_AUTHOR("Reinhard Nissl based on work from Hermann" - " Jung , Frodo Looijaard and" - " Philip Edelbrock "); -MODULE_DESCRIPTION("fujitsu siemens hermes chip driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_fscher_init); -module_exit(sm_fscher_exit); diff --git a/kernel/chips/fscpos.c b/kernel/chips/fscpos.c deleted file mode 100644 index 0bb4858e..00000000 --- a/kernel/chips/fscpos.c +++ /dev/null @@ -1,684 +0,0 @@ -/* - fscpos.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2001 Hermann Jung - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - fujitsu siemens poseidon chip, - module based on lm80.c - Copyright (c) 1998, 1999 Frodo Looijaard - and Philip Edelbrock -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x73, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(fscpos); - -/* The FSCPOS registers */ - -/* chip identification */ -#define FSCPOS_REG_IDENT_0 0x00 -#define FSCPOS_REG_IDENT_1 0x01 -#define FSCPOS_REG_IDENT_2 0x02 -#define FSCPOS_REG_REVISION 0x03 - -/* global control and status */ -#define FSCPOS_REG_EVENT_STATE 0x04 -#define FSCPOS_REG_CONTROL 0x05 - -/* watchdog */ -#define FSCPOS_REG_WDOG_PRESET 0x28 -#define FSCPOS_REG_WDOG_STATE 0x23 -#define FSCPOS_REG_WDOG_CONTROL 0x21 - -/* fan 0 */ -#define FSCPOS_REG_FAN0_MIN 0x55 -#define FSCPOS_REG_FAN0_ACT 0x0e -#define FSCPOS_REG_FAN0_STATE 0x0d -#define FSCPOS_REG_FAN0_RIPPLE 0x0f - -/* fan 1 */ -#define FSCPOS_REG_FAN1_MIN 0x65 -#define FSCPOS_REG_FAN1_ACT 0x6b -#define FSCPOS_REG_FAN1_STATE 0x62 -#define FSCPOS_REG_FAN1_RIPPLE 0x6f - -/* fan 2 */ -/* min speed fan2 not supported */ -#define FSCPOS_REG_FAN2_ACT 0xab -#define FSCPOS_REG_FAN2_STATE 0xa2 -#define FSCPOS_REG_FAN2_RIPPLE 0x0af - -/* voltage supervision */ -#define FSCPOS_REG_VOLT_12 0x45 -#define FSCPOS_REG_VOLT_5 0x42 -#define FSCPOS_REG_VOLT_BATT 0x48 - -/* temperatures */ -/* sensor 0 */ -#define FSCPOS_REG_TEMP0_ACT 0x64 -#define FSCPOS_REG_TEMP0_STATE 0x71 - -/* sensor 1 */ -#define FSCPOS_REG_TEMP1_ACT 0x32 -#define FSCPOS_REG_TEMP1_STATE 0x81 - -/* sensor 2 */ -#define FSCPOS_REG_TEMP2_ACT 0x35 -#define FSCPOS_REG_TEMP2_STATE 0x91 - - - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - -#define IN_TO_REG(val,nr) (SENSORS_LIMIT((val),0,255)) -#define IN_FROM_REG(val,nr) (val) - -/* Initial limits */ - -/* For each registered FSCPOS, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new fscpos client is - allocated. */ -struct fscpos_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 revision; /* revision of chip */ - u8 global_event; /* global event status */ - u8 global_control; /* global control register */ - u8 watchdog[3]; /* watchdog */ - u8 volt[3]; /* 12, 5, battery current */ - u8 temp_act[3]; /* temperature */ - u8 temp_status[3]; /* status of sensor */ - u8 fan_act[3]; /* fans revolutions per second */ - u8 fan_status[3]; /* fan status */ - u8 fan_min[3]; /* fan min value for rps */ - u8 fan_ripple[3]; /* divider for rps */ -}; - - -static int fscpos_attach_adapter(struct i2c_adapter *adapter); -static int fscpos_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int fscpos_detach_client(struct i2c_client *client); - -static int fscpos_read_value(struct i2c_client *client, u8 register); -static int fscpos_write_value(struct i2c_client *client, u8 register, - u8 value); -static void fscpos_update_client(struct i2c_client *client); -static void fscpos_init_client(struct i2c_client *client); - - -static void fscpos_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void fscpos_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscpos_fan_internal(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results, - int nr, int reg_state, int reg_min, int res_ripple); -static void fscpos_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscpos_volt(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscpos_wdog(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver fscpos_driver = { - .name = "FSCPOS sensor driver", - .id = I2C_DRIVERID_FSCPOS, - .flags = I2C_DF_NOTIFY, - .attach_adapter = fscpos_attach_adapter, - .detach_client = fscpos_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define FSCPOS_SYSCTL_VOLT0 1000 /* 12 volt supply */ -#define FSCPOS_SYSCTL_VOLT1 1001 /* 5 volt supply */ -#define FSCPOS_SYSCTL_VOLT2 1002 /* batterie voltage*/ -#define FSCPOS_SYSCTL_FAN0 1101 /* state, min, ripple, actual value fan 0 */ -#define FSCPOS_SYSCTL_FAN1 1102 /* state, min, ripple, actual value fan 1 */ -#define FSCPOS_SYSCTL_FAN2 1103 /* state, min, ripple, actual value fan 2 */ -#define FSCPOS_SYSCTL_TEMP0 1201 /* state and value of sensor 0, cpu die */ -#define FSCPOS_SYSCTL_TEMP1 1202 /* state and value of sensor 1, motherboard */ -#define FSCPOS_SYSCTL_TEMP2 1203 /* state and value of sensor 2, chassis */ -#define FSCPOS_SYSCTL_REV 2000 /* Revision */ -#define FSCPOS_SYSCTL_EVENT 2001 /* global event status */ -#define FSCPOS_SYSCTL_CONTROL 2002 /* global control byte */ -#define FSCPOS_SYSCTL_WDOG 2003 /* state, min, ripple, actual value fan 2 */ -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected FSCPOS. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table fscpos_dir_table_template[] = { - {FSCPOS_SYSCTL_REV, "rev", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_in}, - {FSCPOS_SYSCTL_EVENT, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_in}, - {FSCPOS_SYSCTL_CONTROL, "control", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_in}, - {FSCPOS_SYSCTL_TEMP0, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_temp}, - {FSCPOS_SYSCTL_TEMP1, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_temp}, - {FSCPOS_SYSCTL_TEMP2, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_temp}, - {FSCPOS_SYSCTL_VOLT0, "in0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_volt}, - {FSCPOS_SYSCTL_VOLT1, "in1", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_volt}, - {FSCPOS_SYSCTL_VOLT2, "in2", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_volt}, - {FSCPOS_SYSCTL_FAN0, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_fan}, - {FSCPOS_SYSCTL_FAN1, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_fan}, - {FSCPOS_SYSCTL_FAN2, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_fan}, - {FSCPOS_SYSCTL_WDOG, "wdog", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscpos_wdog}, - {0} -}; - -static int fscpos_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, fscpos_detect); -} - -static int fscpos_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct fscpos_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("fscpos.o: fscpos_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access fscpos_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct fscpos_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &fscpos_driver; - new_client->flags = 0; - - /* Do the remaining detection unless force or force_fscpos parameter */ - if (kind < 0) { - if (fscpos_read_value(new_client, FSCPOS_REG_IDENT_0) != 0x50) - goto ERROR1; - if (fscpos_read_value(new_client, FSCPOS_REG_IDENT_1) != 0x45) - goto ERROR1; - if (fscpos_read_value(new_client, FSCPOS_REG_IDENT_2) != 0x47) - goto ERROR1; - } - - kind = fscpos; - - type_name = "fscpos"; - client_name = "fsc poseidon chip"; - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - fscpos_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - fscpos_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int fscpos_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct fscpos_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("fscpos.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -static int fscpos_read_value(struct i2c_client *client, u8 reg) -{ -#ifdef DEBUG - printk("fscpos: read reg 0x%02x\n",reg); -#endif - return i2c_smbus_read_byte_data(client, reg); -} - -static int fscpos_write_value(struct i2c_client *client, u8 reg, u8 value) -{ -#ifdef DEBUG - printk("fscpos: write reg 0x%02x, val 0x%02x\n",reg, value); -#endif - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new FSCPOS. */ -static void fscpos_init_client(struct i2c_client *client) -{ - struct fscpos_data *data = client->data; - - /* read revision from chip */ - data->revision = fscpos_read_value(client,FSCPOS_REG_REVISION); - /* setup missing fan2_min value */ - data->fan_min[2] = 0xff; -} - -static void fscpos_update_client(struct i2c_client *client) -{ - struct fscpos_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 2 * HZ) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting fscpos update\n"); -#endif - data->temp_act[0] = fscpos_read_value(client, FSCPOS_REG_TEMP0_ACT); - data->temp_act[1] = fscpos_read_value(client, FSCPOS_REG_TEMP1_ACT); - data->temp_act[2] = fscpos_read_value(client, FSCPOS_REG_TEMP2_ACT); - data->temp_status[0] = fscpos_read_value(client, FSCPOS_REG_TEMP0_STATE); - data->temp_status[1] = fscpos_read_value(client, FSCPOS_REG_TEMP1_STATE); - data->temp_status[2] = fscpos_read_value(client, FSCPOS_REG_TEMP2_STATE); - - data->volt[0] = fscpos_read_value(client, FSCPOS_REG_VOLT_12); - data->volt[1] = fscpos_read_value(client, FSCPOS_REG_VOLT_5); - data->volt[2] = fscpos_read_value(client, FSCPOS_REG_VOLT_BATT); - - data->fan_act[0] = fscpos_read_value(client, FSCPOS_REG_FAN0_ACT); - data->fan_act[1] = fscpos_read_value(client, FSCPOS_REG_FAN1_ACT); - data->fan_act[2] = fscpos_read_value(client, FSCPOS_REG_FAN2_ACT); - data->fan_status[0] = fscpos_read_value(client, FSCPOS_REG_FAN0_STATE); - data->fan_status[1] = fscpos_read_value(client, FSCPOS_REG_FAN1_STATE); - data->fan_status[2] = fscpos_read_value(client, FSCPOS_REG_FAN2_STATE); - data->fan_min[0] = fscpos_read_value(client, FSCPOS_REG_FAN0_MIN); - data->fan_min[1] = fscpos_read_value(client, FSCPOS_REG_FAN1_MIN); - /* fan2_min is not supported */ - data->fan_ripple[0] = fscpos_read_value(client, FSCPOS_REG_FAN0_RIPPLE); - data->fan_ripple[1] = fscpos_read_value(client, FSCPOS_REG_FAN1_RIPPLE); - data->fan_ripple[2] = fscpos_read_value(client, FSCPOS_REG_FAN2_RIPPLE); - - data->watchdog[0] = fscpos_read_value(client, FSCPOS_REG_WDOG_PRESET); - data->watchdog[1] = fscpos_read_value(client, FSCPOS_REG_WDOG_STATE); - data->watchdog[2] = fscpos_read_value(client, FSCPOS_REG_WDOG_CONTROL); - - data->global_event = fscpos_read_value(client, FSCPOS_REG_EVENT_STATE); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void fscpos_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscpos_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscpos_update_client(client); - switch(ctl_name) { - case FSCPOS_SYSCTL_REV: - results[0] = data->revision ; - break; - case FSCPOS_SYSCTL_EVENT: - results[0] = data->global_event & 0x1f; - break; - case FSCPOS_SYSCTL_CONTROL: - results[0] = data->global_control & 0x01; - break; - default: - printk("fscpos: ctl_name %d not supported\n", - ctl_name); - *nrels_mag = 0; - return; - } - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if((ctl_name == FSCPOS_SYSCTL_CONTROL) && (*nrels_mag >= 1)) { - data->global_control = (results[0] & 0x01); - printk("fscpos: writing 0x%02x to global_control\n", - data->global_control); - fscpos_write_value(client,FSCPOS_REG_CONTROL, - data->global_control); - } - else - printk("fscpos: writing to chip not supported\n"); - } -} - -#define TEMP_FROM_REG(val) (val-128) - - -void fscpos_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscpos_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscpos_update_client(client); - switch(ctl_name) { - case FSCPOS_SYSCTL_TEMP0: - results[0] = data->temp_status[0] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[0]); - break; - case FSCPOS_SYSCTL_TEMP1: - results[0] = data->temp_status[1] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[1]); - break; - case FSCPOS_SYSCTL_TEMP2: - results[0] = data->temp_status[2] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[2]); - break; - default: - printk("fscpos: ctl_name %d not supported\n", - ctl_name); - *nrels_mag = 0; - return; - } - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if(*nrels_mag >= 1) { - switch(ctl_name) { - case FSCPOS_SYSCTL_TEMP0: - data->temp_status[0] = - (data->temp_status[0] & ~0x02) - | (results[0] & 0x02); - printk("fscpos: writing value 0x%02x " - "to temp0_status\n", - data->temp_status[0]); - fscpos_write_value(client, - FSCPOS_REG_TEMP0_STATE, - data->temp_status[0] & 0x02); - break; - case FSCPOS_SYSCTL_TEMP1: - data->temp_status[1] = (data->temp_status[1] & ~0x02) | (results[0] & 0x02); - printk("fscpos: writing value 0x%02x to temp1_status\n", data->temp_status[1]); - fscpos_write_value(client,FSCPOS_REG_TEMP1_STATE, - data->temp_status[1] & 0x02); - break; - case FSCPOS_SYSCTL_TEMP2: - data->temp_status[2] = (data->temp_status[2] & ~0x02) | (results[0] & 0x02); - printk("fscpos: writing value 0x%02x to temp2_status\n", data->temp_status[2]); - fscpos_write_value(client,FSCPOS_REG_TEMP2_STATE, - data->temp_status[2] & 0x02); - break; - default: - printk("fscpos: ctl_name %d not supported\n",ctl_name); - } - } - else - printk("fscpos: writing to chip not supported\n"); - } -} - -#define VOLT_FROM_REG(val,mult) (val*mult/255) - -void fscpos_volt(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscpos_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - fscpos_update_client(client); - switch(ctl_name) { - case FSCPOS_SYSCTL_VOLT0: - results[0] = VOLT_FROM_REG(data->volt[0],1420); - break; - case FSCPOS_SYSCTL_VOLT1: - results[0] = VOLT_FROM_REG(data->volt[1],660); - break; - case FSCPOS_SYSCTL_VOLT2: - results[0] = VOLT_FROM_REG(data->volt[2],330); - break; - default: - printk("fscpos: ctl_name %d not supported\n", - ctl_name); - *nrels_mag = 0; - return; - } - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - printk("fscpos: writing to chip not supported\n"); - } -} - -void fscpos_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - - switch(ctl_name) { - case FSCPOS_SYSCTL_FAN0: - fscpos_fan_internal(client,operation,ctl_name,nrels_mag,results, - 0,FSCPOS_REG_FAN0_STATE,FSCPOS_REG_FAN0_MIN, - FSCPOS_REG_FAN0_RIPPLE); - break; - case FSCPOS_SYSCTL_FAN1: - fscpos_fan_internal(client,operation,ctl_name,nrels_mag,results, - 1,FSCPOS_REG_FAN1_STATE,FSCPOS_REG_FAN1_MIN, - FSCPOS_REG_FAN1_RIPPLE); - break; - case FSCPOS_SYSCTL_FAN2: - fscpos_fan_internal(client,operation,ctl_name,nrels_mag,results, - 2,FSCPOS_REG_FAN2_STATE,0xff, - FSCPOS_REG_FAN2_RIPPLE); - break; - default: - printk("fscpos: illegal fan nr %d\n",ctl_name); - } -} - -#define RPM_FROM_REG(val) (val*60) - -void fscpos_fan_internal(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results, int nr, - int reg_state, int reg_min, int reg_ripple ) -{ - struct fscpos_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscpos_update_client(client); - results[0] = data->fan_status[nr] & 0x04; - results[1] = data->fan_min[nr]; - results[2] = data->fan_ripple[nr] & 0x03; - results[3] = RPM_FROM_REG(data->fan_act[nr]); - *nrels_mag = 4; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if(*nrels_mag >= 1) { - data->fan_status[nr] = results[0] & 0x04; - printk("fscpos: writing value 0x%02x to fan%d_status\n", - data->fan_status[nr],nr); - fscpos_write_value(client,reg_state, - data->fan_status[nr]); - } - if((*nrels_mag >= 2) && (nr < 2)) { - /* minimal speed for fan2 not supported */ - data->fan_min[nr] = results[1]; - printk("fscpos: writing value 0x%02x to fan%d_min\n", - data->fan_min[nr],nr); - fscpos_write_value(client,reg_min, - data->fan_min[nr]); - } - if(*nrels_mag >= 3) { - if((results[2] & 0x03) == 0) { - printk("fscpos: fan%d ripple 0 not allowed\n",nr); - return; - } - data->fan_ripple[nr] = results[2] & 0x03; - printk("fscpos: writing value 0x%02x to fan%d_ripple\n", - data->fan_ripple[nr],nr); - fscpos_write_value(client,reg_ripple, - data->fan_ripple[nr]); - } - } -} - -void fscpos_wdog(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscpos_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscpos_update_client(client); - results[0] = data->watchdog[0] ; - results[1] = data->watchdog[1] & 0x02; - results[2] = data->watchdog[2] & 0xb0; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->watchdog[0] = results[0] & 0xff; - printk("fscpos: writing value 0x%02x to wdog_preset\n", - data->watchdog[0]); - fscpos_write_value(client,FSCPOS_REG_WDOG_PRESET, - data->watchdog[0]); - } - if (*nrels_mag >= 2) { - data->watchdog[1] = results[1] & 0x02; - printk("fscpos: writing value 0x%02x to wdog_state\n", - data->watchdog[1]); - fscpos_write_value(client,FSCPOS_REG_WDOG_STATE, - data->watchdog[1]); - } - if (*nrels_mag >= 3) { - data->watchdog[2] = results[2] & 0xb0; - printk("fscpos: writing value 0x%02x to wdog_control\n", - data->watchdog[2]); - fscpos_write_value(client,FSCPOS_REG_WDOG_CONTROL, - data->watchdog[2]); - } - } -} - -static int __init sm_fscpos_init(void) -{ - printk("fscpos.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&fscpos_driver); -} - -static void __exit sm_fscpos_exit(void) -{ - i2c_del_driver(&fscpos_driver); -} - - - -MODULE_AUTHOR - ("Hermann Jung based on work from Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("fujitsu siemens poseidon chip driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_fscpos_init); -module_exit(sm_fscpos_exit); diff --git a/kernel/chips/fscscy.c b/kernel/chips/fscscy.c deleted file mode 100644 index 559a106b..00000000 --- a/kernel/chips/fscscy.c +++ /dev/null @@ -1,909 +0,0 @@ -/* - fscscy.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2001 Martin Knoblauch - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - fujitsu siemens scylla chip, - module based on lm80.c, fscpos.c - Copyright (c) 1998, 1999 Frodo Looijaard - and Philip Edelbrock -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x73, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(fscscy); - -/* The FSCSCY registers */ - -/* chip identification */ -#define FSCSCY_REG_IDENT_0 0x00 -#define FSCSCY_REG_IDENT_1 0x01 -#define FSCSCY_REG_IDENT_2 0x02 -#define FSCSCY_REG_REVISION 0x03 - -/* global control and status */ -#define FSCSCY_REG_EVENT_STATE 0x04 -#define FSCSCY_REG_CONTROL 0x05 - -/* watchdog */ -#define FSCSCY_REG_WDOG_PRESET 0x28 -#define FSCSCY_REG_WDOG_STATE 0x23 -#define FSCSCY_REG_WDOG_CONTROL 0x21 - -/* -** Fan definitions -** -** _RPMMIN: Minimum speed. Can be set via interface, but only for three of the fans -** FAN1_RPMMIN is wired to Fan 0 (CPU Fans) -** FAN4_RPMMIN is wired to Fan 2 (PS Fans ??) -** FAN5_RPMMIN is wired to Fan 3 (AUX Fans ??) -** _ACT: Actual Fan Speed -** _STATE: Fan status register -** _RIPPLE: Fan speed multiplier -*/ - -/* fan 0 */ -#define FSCSCY_REG_FAN0_RPMMIN 0x65 -#define FSCSCY_REG_FAN0_ACT 0x6b -#define FSCSCY_REG_FAN0_STATE 0x62 -#define FSCSCY_REG_FAN0_RIPPLE 0x6f - -/* fan 1 */ -#define FSCSCY_REG_FAN1_RPMMIN FSCSCY_REG_FAN0_RPMMIN -#define FSCSCY_REG_FAN1_ACT 0x6c -#define FSCSCY_REG_FAN1_STATE 0x61 -#define FSCSCY_REG_FAN1_RIPPLE 0x6f - -/* fan 2 */ -#define FSCSCY_REG_FAN2_RPMMIN 0x55 -#define FSCSCY_REG_FAN2_ACT 0x0e -#define FSCSCY_REG_FAN2_STATE 0x0d -#define FSCSCY_REG_FAN2_RIPPLE 0x0f - -/* fan 3 */ -#define FSCSCY_REG_FAN3_RPMMIN 0xa5 -#define FSCSCY_REG_FAN3_ACT 0xab -#define FSCSCY_REG_FAN3_STATE 0xa2 -#define FSCSCY_REG_FAN3_RIPPLE 0xaf - -/* fan 4 */ -#define FSCSCY_REG_FAN4_RPMMIN FSCSCY_REG_FAN2_RPMMIN -#define FSCSCY_REG_FAN4_ACT 0x5c -#define FSCSCY_REG_FAN4_STATE 0x52 -#define FSCSCY_REG_FAN4_RIPPLE 0x0f - -/* fan 5 */ -#define FSCSCY_REG_FAN5_RPMMIN FSCSCY_REG_FAN3_RPMMIN -#define FSCSCY_REG_FAN5_ACT 0xbb -#define FSCSCY_REG_FAN5_STATE 0xb2 -#define FSCSCY_REG_FAN5_RIPPLE 0xbf - -/* voltage supervision */ -#define FSCSCY_REG_VOLT_12 0x45 -#define FSCSCY_REG_VOLT_5 0x42 -#define FSCSCY_REG_VOLT_BATT 0x48 - -/* temperatures */ -/* sensor 0 */ -#define FSCSCY_REG_TEMP0_ACT 0x64 -#define FSCSCY_REG_TEMP0_STATE 0x71 -#define FSCSCY_REG_TEMP0_LIM 0x76 - -/* sensor 1 */ -#define FSCSCY_REG_TEMP1_ACT 0xD0 -#define FSCSCY_REG_TEMP1_STATE 0xD1 -#define FSCSCY_REG_TEMP1_LIM 0xD6 - -/* sensor 2 */ -#define FSCSCY_REG_TEMP2_ACT 0x32 -#define FSCSCY_REG_TEMP2_STATE 0x81 -#define FSCSCY_REG_TEMP2_LIM 0x86 - -/* sensor3 */ -#define FSCSCY_REG_TEMP3_ACT 0x35 -#define FSCSCY_REG_TEMP3_STATE 0x91 -#define FSCSCY_REG_TEMP3_LIM 0x96 - -/* PCI Load */ -#define FSCSCY_REG_PCILOAD 0x1a - -/* Intrusion Sensor */ -#define FSCSCY_REG_INTR_STATE 0x13 -#define FSCSCY_REG_INTR_CTRL 0x12 - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - -#define IN_TO_REG(val,nr) (SENSORS_LIMIT((val),0,255)) -#define IN_FROM_REG(val,nr) (val) - -/* Initial limits */ - -/* For each registered FSCSCY, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new fscscy client is - allocated. */ -struct fscscy_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 revision; /* revision of chip */ - u8 global_event; /* global event status */ - u8 global_control; /* global control register */ - u8 watchdog[3]; /* watchdog */ - u8 volt[3]; /* 12, 5, battery current */ - u8 volt_min[3]; /* minimum voltages over module "lifetime" */ - u8 volt_max[3]; /* maximum voltages over module "lifetime" */ - u8 temp_act[4]; /* temperature */ - u8 temp_status[4]; /* status of temp. sensor */ - u8 temp_lim[4]; /* limit temperature of temp. sensor */ - u8 temp_min[4]; /* minimum of temp. sensor, this is just calculated by the module */ - u8 temp_max[4]; /* maximum of temp. sensor, this is just calculsted by the module */ - u8 fan_act[6]; /* fans revolutions per second */ - u8 fan_status[6]; /* fan status */ - u8 fan_rpmmin[6]; /* fan min value for rps */ - u8 fan_ripple[6]; /* divider for rps */ - u8 fan_min[6]; /* minimum RPM over module "lifetime" */ - u8 fan_max[6]; /* maximum RPM over module "lifetime" */ - u8 pciload; /* PCILoad value */ - u8 intr_status; /* Intrusion Status */ - u8 intr_control; /* Intrusion Control */ -}; - - -static int fscscy_attach_adapter(struct i2c_adapter *adapter); -static int fscscy_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int fscscy_detach_client(struct i2c_client *client); - -static int fscscy_read_value(struct i2c_client *client, u8 register); -static int fscscy_write_value(struct i2c_client *client, u8 register, - u8 value); -static void fscscy_update_client(struct i2c_client *client); -static void fscscy_init_client(struct i2c_client *client); - - -static void fscscy_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void fscscy_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscscy_fan_internal(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results, - int nr, int reg_state, int reg_min, int res_ripple); -static void fscscy_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscscy_volt(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscscy_wdog(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscscy_pciload(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void fscscy_intrusion(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver fscscy_driver = { - .name = "FSCSCY sensor driver", - .id = I2C_DRIVERID_FSCSCY, - .flags = I2C_DF_NOTIFY, - .attach_adapter = fscscy_attach_adapter, - .detach_client = fscscy_detach_client, -}; - -/* The /proc/sys entries */ - -/* -- SENSORS SYSCTL START -- */ -#define FSCSCY_SYSCTL_VOLT0 1000 /* 12 volt supply */ -#define FSCSCY_SYSCTL_VOLT1 1001 /* 5 volt supply */ -#define FSCSCY_SYSCTL_VOLT2 1002 /* batterie voltage*/ -#define FSCSCY_SYSCTL_FAN0 1101 /* state, min, ripple, actual value fan 0 */ -#define FSCSCY_SYSCTL_FAN1 1102 /* state, min, ripple, actual value fan 1 */ -#define FSCSCY_SYSCTL_FAN2 1103 /* state, min, ripple, actual value fan 2 */ -#define FSCSCY_SYSCTL_FAN3 1104 /* state, min, ripple, actual value fan 3 */ -#define FSCSCY_SYSCTL_FAN4 1105 /* state, min, ripple, actual value fan 4 */ -#define FSCSCY_SYSCTL_FAN5 1106 /* state, min, ripple, actual value fan 5 */ -#define FSCSCY_SYSCTL_TEMP0 1201 /* state and value of sensor 0, cpu die */ -#define FSCSCY_SYSCTL_TEMP1 1202 /* state and value of sensor 1, motherboard */ -#define FSCSCY_SYSCTL_TEMP2 1203 /* state and value of sensor 2, chassis */ -#define FSCSCY_SYSCTL_TEMP3 1204 /* state and value of sensor 3, chassis */ -#define FSCSCY_SYSCTL_REV 2000 /* Revision */ -#define FSCSCY_SYSCTL_EVENT 2001 /* global event status */ -#define FSCSCY_SYSCTL_CONTROL 2002 /* global control byte */ -#define FSCSCY_SYSCTL_WDOG 2003 /* state, min, ripple, actual value fan 2 */ -#define FSCSCY_SYSCTL_PCILOAD 2004 /* PCILoad value */ -#define FSCSCY_SYSCTL_INTRUSION 2005 /* state, control for intrusion sensor */ - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected FSCSCY. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table fscscy_dir_table_template[] = { - {FSCSCY_SYSCTL_REV, "rev", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_in}, - {FSCSCY_SYSCTL_EVENT, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_in}, - {FSCSCY_SYSCTL_CONTROL, "control", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_in}, - {FSCSCY_SYSCTL_TEMP0, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_temp}, - {FSCSCY_SYSCTL_TEMP1, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_temp}, - {FSCSCY_SYSCTL_TEMP2, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_temp}, - {FSCSCY_SYSCTL_TEMP3, "temp4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_temp}, - {FSCSCY_SYSCTL_VOLT0, "in0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_volt}, - {FSCSCY_SYSCTL_VOLT1, "in1", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_volt}, - {FSCSCY_SYSCTL_VOLT2, "in2", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_volt}, - {FSCSCY_SYSCTL_FAN0, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_fan}, - {FSCSCY_SYSCTL_FAN1, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_fan}, - {FSCSCY_SYSCTL_FAN2, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_fan}, - {FSCSCY_SYSCTL_FAN3, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_fan}, - {FSCSCY_SYSCTL_FAN4, "fan5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_fan}, - {FSCSCY_SYSCTL_FAN5, "fan6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_fan}, - {FSCSCY_SYSCTL_WDOG, "wdog", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_wdog}, - {FSCSCY_SYSCTL_PCILOAD, "pciload", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_pciload}, - {FSCSCY_SYSCTL_INTRUSION, "intrusion", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &fscscy_intrusion}, - {0} -}; - -static int fscscy_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, fscscy_detect); -} - -int fscscy_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct fscscy_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("fscscy.o: fscscy_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access fscscy_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct fscscy_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &fscscy_driver; - new_client->flags = 0; - - /* Do the remaining detection unless force or force_fscscy parameter */ - if (kind < 0) { - if (fscscy_read_value(new_client, FSCSCY_REG_IDENT_0) != 0x53) - goto ERROR1; - if (fscscy_read_value(new_client, FSCSCY_REG_IDENT_1) != 0x43) - goto ERROR1; - if (fscscy_read_value(new_client, FSCSCY_REG_IDENT_2) != 0x59) - goto ERROR1; - } - - kind = fscscy; - - type_name = "fscscy"; - client_name = "fsc scylla chip"; - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - fscscy_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - fscscy_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int fscscy_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct fscscy_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("fscscy.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -static int fscscy_read_value(struct i2c_client *client, u8 reg) -{ -#ifdef DEBUG - printk("fscscy: read reg 0x%02x\n",reg); -#endif - return i2c_smbus_read_byte_data(client, reg); -} - -static int fscscy_write_value(struct i2c_client *client, u8 reg, u8 value) -{ -#ifdef DEBUG - printk("fscscy: write reg 0x%02x, val 0x%02x\n",reg, value); -#endif - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new FSCSCY. */ -static void fscscy_init_client(struct i2c_client *client) -{ - struct fscscy_data *data = client->data; - - /* read revision from chip */ - data->revision = fscscy_read_value(client,FSCSCY_REG_REVISION); - - /* Initialize min/max values from chip */ - data->fan_min[0] = data->fan_max[0] = fscscy_read_value(client, FSCSCY_REG_FAN0_ACT); - data->fan_min[1] = data->fan_max[1] = fscscy_read_value(client, FSCSCY_REG_FAN1_ACT); - data->fan_min[2] = data->fan_max[2] = fscscy_read_value(client, FSCSCY_REG_FAN2_ACT); - data->fan_min[3] = data->fan_max[3] = fscscy_read_value(client, FSCSCY_REG_FAN3_ACT); - data->fan_min[4] = data->fan_max[4] = fscscy_read_value(client, FSCSCY_REG_FAN4_ACT); - data->fan_min[4] = data->fan_max[5] = fscscy_read_value(client, FSCSCY_REG_FAN5_ACT); - data->temp_min[0] = data->temp_max[0] = fscscy_read_value(client, FSCSCY_REG_TEMP0_ACT); - data->temp_min[1] = data->temp_max[1] = fscscy_read_value(client, FSCSCY_REG_TEMP1_ACT); - data->temp_min[2] = data->temp_max[2] = fscscy_read_value(client, FSCSCY_REG_TEMP2_ACT); - data->temp_min[3] = data->temp_max[3] = fscscy_read_value(client, FSCSCY_REG_TEMP3_ACT); - data->volt_min[0] = data->volt_max[0] = fscscy_read_value(client, FSCSCY_REG_VOLT_12); - data->volt_min[1] = data->volt_max[1] = fscscy_read_value(client, FSCSCY_REG_VOLT_5); - data->volt_min[2] = data->volt_max[2] = fscscy_read_value(client, FSCSCY_REG_VOLT_BATT); -} - -static void fscscy_update_client(struct i2c_client *client) -{ - struct fscscy_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 2 * HZ) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting fscscy update\n"); -#endif - data->temp_act[0] = fscscy_read_value(client, FSCSCY_REG_TEMP0_ACT); - if (data->temp_min[0] > data->temp_act[0]) data->temp_min[0] = data->temp_act[0]; - if (data->temp_max[0] < data->temp_act[0]) data->temp_max[0] = data->temp_act[0]; - data->temp_act[1] = fscscy_read_value(client, FSCSCY_REG_TEMP1_ACT); - if (data->temp_min[1] > data->temp_act[1]) data->temp_min[1] = data->temp_act[1]; - if (data->temp_max[1] < data->temp_act[1]) data->temp_max[1] = data->temp_act[1]; - data->temp_act[2] = fscscy_read_value(client, FSCSCY_REG_TEMP2_ACT); - if (data->temp_min[2] > data->temp_act[2]) data->temp_min[2] = data->temp_act[2]; - if (data->temp_max[2] < data->temp_act[2]) data->temp_max[2] = data->temp_act[2]; - data->temp_act[3] = fscscy_read_value(client, FSCSCY_REG_TEMP3_ACT); - if (data->temp_min[3] > data->temp_act[3]) data->temp_min[3] = data->temp_act[3]; - if (data->temp_max[3] < data->temp_act[3]) data->temp_max[3] = data->temp_act[3]; - data->temp_status[0] = fscscy_read_value(client, FSCSCY_REG_TEMP0_STATE); - data->temp_status[1] = fscscy_read_value(client, FSCSCY_REG_TEMP1_STATE); - data->temp_status[2] = fscscy_read_value(client, FSCSCY_REG_TEMP2_STATE); - data->temp_status[3] = fscscy_read_value(client, FSCSCY_REG_TEMP3_STATE); - data->temp_lim[0] = fscscy_read_value(client, FSCSCY_REG_TEMP0_LIM); - data->temp_lim[1] = fscscy_read_value(client, FSCSCY_REG_TEMP1_LIM); - data->temp_lim[2] = fscscy_read_value(client, FSCSCY_REG_TEMP2_LIM); - data->temp_lim[3] = fscscy_read_value(client, FSCSCY_REG_TEMP3_LIM); - - data->volt[0] = fscscy_read_value(client, FSCSCY_REG_VOLT_12); - if (data->volt_min[0] > data->volt[0]) data->volt_min[0] = data->volt[0]; - if (data->volt_max[0] < data->volt[0]) data->volt_max[0] = data->volt[0]; - data->volt[1] = fscscy_read_value(client, FSCSCY_REG_VOLT_5); - if (data->volt_min[1] > data->volt[1]) data->volt_min[1] = data->volt[1]; - if (data->volt_max[1] < data->volt[1]) data->volt_max[1] = data->volt[1]; - data->volt[2] = fscscy_read_value(client, FSCSCY_REG_VOLT_BATT); - if (data->volt_min[2] > data->volt[2]) data->volt_min[2] = data->volt[2]; - if (data->volt_max[2] < data->volt[2]) data->volt_max[2] = data->volt[2]; - - data->fan_act[0] = fscscy_read_value(client, FSCSCY_REG_FAN0_ACT); - if (data->fan_min[0] > data->fan_act[0]) data->fan_min[0] = data->fan_act[0]; - if (data->fan_max[0] < data->fan_act[0]) data->fan_max[0] = data->fan_act[0]; - data->fan_act[1] = fscscy_read_value(client, FSCSCY_REG_FAN1_ACT); - if (data->fan_min[1] > data->fan_act[1]) data->fan_min[1] = data->fan_act[1]; - if (data->fan_max[1] < data->fan_act[1]) data->fan_max[1] = data->fan_act[1]; - data->fan_act[2] = fscscy_read_value(client, FSCSCY_REG_FAN2_ACT); - if (data->fan_min[2] > data->fan_act[2]) data->fan_min[2] = data->fan_act[2]; - if (data->fan_max[2] < data->fan_act[2]) data->fan_max[2] = data->fan_act[2]; - data->fan_act[3] = fscscy_read_value(client, FSCSCY_REG_FAN3_ACT); - if (data->fan_min[3] > data->fan_act[3]) data->fan_min[3] = data->fan_act[3]; - if (data->fan_max[3] < data->fan_act[3]) data->fan_max[3] = data->fan_act[3]; - data->fan_act[4] = fscscy_read_value(client, FSCSCY_REG_FAN4_ACT); - if (data->fan_min[4] > data->fan_act[4]) data->fan_min[4] = data->fan_act[4]; - if (data->fan_max[4] < data->fan_act[4]) data->fan_max[4] = data->fan_act[4]; - data->fan_act[5] = fscscy_read_value(client, FSCSCY_REG_FAN5_ACT); - if (data->fan_min[5] > data->fan_act[5]) data->fan_min[5] = data->fan_act[5]; - if (data->fan_max[5] < data->fan_act[5]) data->fan_max[5] = data->fan_act[5]; - data->fan_status[0] = fscscy_read_value(client, FSCSCY_REG_FAN0_STATE); - data->fan_status[1] = fscscy_read_value(client, FSCSCY_REG_FAN1_STATE); - data->fan_status[2] = fscscy_read_value(client, FSCSCY_REG_FAN2_STATE); - data->fan_status[3] = fscscy_read_value(client, FSCSCY_REG_FAN3_STATE); - data->fan_status[4] = fscscy_read_value(client, FSCSCY_REG_FAN4_STATE); - data->fan_status[5] = fscscy_read_value(client, FSCSCY_REG_FAN5_STATE); - data->fan_rpmmin[0] = fscscy_read_value(client, FSCSCY_REG_FAN0_RPMMIN); - data->fan_rpmmin[1] = fscscy_read_value(client, FSCSCY_REG_FAN1_RPMMIN); - data->fan_rpmmin[2] = fscscy_read_value(client, FSCSCY_REG_FAN2_RPMMIN); - data->fan_rpmmin[3] = fscscy_read_value(client, FSCSCY_REG_FAN3_RPMMIN); - data->fan_rpmmin[4] = fscscy_read_value(client, FSCSCY_REG_FAN4_RPMMIN); - data->fan_rpmmin[5] = fscscy_read_value(client, FSCSCY_REG_FAN5_RPMMIN); - data->fan_ripple[0] = fscscy_read_value(client, FSCSCY_REG_FAN0_RIPPLE); - data->fan_ripple[1] = fscscy_read_value(client, FSCSCY_REG_FAN1_RIPPLE); - data->fan_ripple[2] = fscscy_read_value(client, FSCSCY_REG_FAN2_RIPPLE); - data->fan_ripple[3] = fscscy_read_value(client, FSCSCY_REG_FAN3_RIPPLE); - data->fan_ripple[4] = fscscy_read_value(client, FSCSCY_REG_FAN4_RIPPLE); - data->fan_ripple[5] = fscscy_read_value(client, FSCSCY_REG_FAN5_RIPPLE); - - data->watchdog[0] = fscscy_read_value(client, FSCSCY_REG_WDOG_PRESET); - data->watchdog[1] = fscscy_read_value(client, FSCSCY_REG_WDOG_STATE); - data->watchdog[2] = fscscy_read_value(client, FSCSCY_REG_WDOG_CONTROL); - - data->global_event = fscscy_read_value(client, FSCSCY_REG_EVENT_STATE); - data->global_control = fscscy_read_value(client, FSCSCY_REG_CONTROL); - data->pciload = fscscy_read_value(client, FSCSCY_REG_PCILOAD); - data->intr_status = fscscy_read_value(client, FSCSCY_REG_INTR_STATE); - data->intr_control = fscscy_read_value(client, FSCSCY_REG_INTR_CTRL); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void fscscy_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscscy_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscscy_update_client(client); - switch(ctl_name) { - case FSCSCY_SYSCTL_REV: - results[0] = data->revision ; - break; - case FSCSCY_SYSCTL_EVENT: - results[0] = data->global_event & 0x9f; /* MKN */ - break; - case FSCSCY_SYSCTL_CONTROL: - results[0] = data->global_control & 0x19; /* MKN */ - break; - default: - printk("fscscy: ctl_name %d not supported\n", - ctl_name); - *nrels_mag = 0; - return; - } - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if((ctl_name == FSCSCY_SYSCTL_CONTROL) && (*nrels_mag >= 1)) { - data->global_control = (data->global_control & 0x18) | (results[0] & 0x01); /* MKN */ - printk("fscscy: writing 0x%02x to global_control\n", - data->global_control); - fscscy_write_value(client,FSCSCY_REG_CONTROL, - data->global_control); - } - else - printk("fscscy: writing to chip not supported\n"); - } -} - -#define TEMP_FROM_REG(val) (val-128) - - -void fscscy_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscscy_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscscy_update_client(client); - switch(ctl_name) { - case FSCSCY_SYSCTL_TEMP0: - results[0] = data->temp_status[0] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[0]); - results[2] = TEMP_FROM_REG(data->temp_lim[0]); - results[3] = TEMP_FROM_REG(data->temp_min[0]); - results[4] = TEMP_FROM_REG(data->temp_max[0]); - break; - case FSCSCY_SYSCTL_TEMP1: - results[0] = data->temp_status[1] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[1]); - results[2] = TEMP_FROM_REG(data->temp_lim[1]); - results[3] = TEMP_FROM_REG(data->temp_min[1]); - results[4] = TEMP_FROM_REG(data->temp_max[1]); - break; - case FSCSCY_SYSCTL_TEMP2: - results[0] = data->temp_status[2] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[2]); - results[2] = TEMP_FROM_REG(data->temp_lim[2]); - results[3] = TEMP_FROM_REG(data->temp_min[2]); - results[4] = TEMP_FROM_REG(data->temp_max[2]); - break; - case FSCSCY_SYSCTL_TEMP3: - results[0] = data->temp_status[3] & 0x03; - results[1] = TEMP_FROM_REG(data->temp_act[3]); - results[2] = TEMP_FROM_REG(data->temp_lim[3]); - results[3] = TEMP_FROM_REG(data->temp_min[3]); - results[4] = TEMP_FROM_REG(data->temp_max[3]); - break; - default: - printk("fscscy: ctl_name %d not supported\n", - ctl_name); - *nrels_mag = 0; - return; - } - *nrels_mag = 5; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if(*nrels_mag >= 1) { - switch(ctl_name) { - case FSCSCY_SYSCTL_TEMP0: - data->temp_status[0] = - (data->temp_status[0] & ~0x02) - | (results[0] & 0x02); - printk("fscscy: writing value 0x%02x " - "to temp0_status\n", - data->temp_status[0]); - fscscy_write_value(client, - FSCSCY_REG_TEMP0_STATE, - data->temp_status[0] & 0x02); - break; - case FSCSCY_SYSCTL_TEMP1: - data->temp_status[1] = (data->temp_status[1] & ~0x02) | (results[0] & 0x02); - printk("fscscy: writing value 0x%02x to temp1_status\n", data->temp_status[1]); - fscscy_write_value(client,FSCSCY_REG_TEMP1_STATE, - data->temp_status[1] & 0x02); - break; - case FSCSCY_SYSCTL_TEMP2: - data->temp_status[2] = (data->temp_status[2] & ~0x02) | (results[0] & 0x02); - printk("fscscy: writing value 0x%02x to temp2_status\n", data->temp_status[2]); - fscscy_write_value(client,FSCSCY_REG_TEMP2_STATE, - data->temp_status[2] & 0x02); - break; - case FSCSCY_SYSCTL_TEMP3: - data->temp_status[3] = (data->temp_status[3] & ~0x02) | (results[0] & 0x02); - printk("fscscy: writing value 0x%02x to temp3_status\n", data->temp_status[3]); - fscscy_write_value(client,FSCSCY_REG_TEMP3_STATE, - data->temp_status[3] & 0x02); - break; - default: - printk("fscscy: ctl_name %d not supported\n",ctl_name); - } - } - else - printk("fscscy: writing to chip not supported\n"); - } -} - -#define VOLT_FROM_REG(val,mult) (val*mult/255) - -void fscscy_volt(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscscy_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - fscscy_update_client(client); - switch(ctl_name) { - case FSCSCY_SYSCTL_VOLT0: - results[0] = VOLT_FROM_REG(data->volt[0],1420); - results[1] = VOLT_FROM_REG(data->volt_min[0],1420); - results[2] = VOLT_FROM_REG(data->volt_max[0],1420); - break; - case FSCSCY_SYSCTL_VOLT1: - results[0] = VOLT_FROM_REG(data->volt[1],660); - results[1] = VOLT_FROM_REG(data->volt_min[1],660); - results[2] = VOLT_FROM_REG(data->volt_max[1],660); - break; - case FSCSCY_SYSCTL_VOLT2: - results[0] = VOLT_FROM_REG(data->volt[2],330); - results[1] = VOLT_FROM_REG(data->volt_min[2],330); - results[2] = VOLT_FROM_REG(data->volt_max[2],330); - break; - default: - printk("fscscy: ctl_name %d not supported\n", - ctl_name); - *nrels_mag = 0; - return; - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - printk("fscscy: writing to chip not supported\n"); - } -} - -void fscscy_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - - switch(ctl_name) { - case FSCSCY_SYSCTL_FAN0: - fscscy_fan_internal(client,operation,ctl_name,nrels_mag,results, - 0,FSCSCY_REG_FAN0_STATE,FSCSCY_REG_FAN0_RPMMIN, - FSCSCY_REG_FAN0_RIPPLE); - break; - case FSCSCY_SYSCTL_FAN1: - fscscy_fan_internal(client,operation,ctl_name,nrels_mag,results, - 1,FSCSCY_REG_FAN1_STATE,FSCSCY_REG_FAN1_RPMMIN, - FSCSCY_REG_FAN1_RIPPLE); - break; - case FSCSCY_SYSCTL_FAN2: - fscscy_fan_internal(client,operation,ctl_name,nrels_mag,results, - 2,FSCSCY_REG_FAN2_STATE,FSCSCY_REG_FAN2_RPMMIN, - FSCSCY_REG_FAN2_RIPPLE); - break; - case FSCSCY_SYSCTL_FAN3: - fscscy_fan_internal(client,operation,ctl_name,nrels_mag,results, - 3,FSCSCY_REG_FAN3_STATE,FSCSCY_REG_FAN3_RPMMIN, - FSCSCY_REG_FAN3_RIPPLE); - break; - case FSCSCY_SYSCTL_FAN4: - fscscy_fan_internal(client,operation,ctl_name,nrels_mag,results, - 4,FSCSCY_REG_FAN4_STATE,FSCSCY_REG_FAN4_RPMMIN, - FSCSCY_REG_FAN4_RIPPLE); - break; - case FSCSCY_SYSCTL_FAN5: - fscscy_fan_internal(client,operation,ctl_name,nrels_mag,results, - 5,FSCSCY_REG_FAN5_STATE,FSCSCY_REG_FAN5_RPMMIN, - FSCSCY_REG_FAN5_RIPPLE); - break; - default: - printk("fscscy: illegal fan nr %d\n",ctl_name); - } -} - -#define RPM_FROM_REG(val) (val*60) - -void fscscy_fan_internal(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results, int nr, - int reg_state, int reg_min, int reg_ripple ) -{ - struct fscscy_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscscy_update_client(client); - results[0] = data->fan_status[nr] & 0x0f; /* MKN */ - results[1] = data->fan_rpmmin[nr]; - results[2] = data->fan_ripple[nr] & 0x03; - results[3] = RPM_FROM_REG(data->fan_act[nr]); - results[4] = RPM_FROM_REG(data->fan_min[nr]); - results[5] = RPM_FROM_REG(data->fan_max[nr]); - *nrels_mag = 6; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if(*nrels_mag >= 1) { - data->fan_status[nr] = (data->fan_status[nr] & 0x0b) | (results[0] & 0x04); /* MKN */ - printk("fscscy: writing value 0x%02x to fan%d_status\n", - data->fan_status[nr],nr); - fscscy_write_value(client,reg_state, - data->fan_status[nr]); - } - if(*nrels_mag >= 2) { - if((results[1] & 0xff) == 0) { - printk("fscscy: fan%d rpmmin 0 not allowed for safety reasons\n",nr); - return; - } - data->fan_rpmmin[nr] = results[1]; - printk("fscscy: writing value 0x%02x to fan%d_min\n", - data->fan_rpmmin[nr],nr); - fscscy_write_value(client,reg_min, - data->fan_rpmmin[nr]); - } - if(*nrels_mag >= 3) { - if((results[2] & 0x03) == 0) { - printk("fscscy: fan%d ripple 0 is nonsense/not allowed\n",nr); - return; - } - data->fan_ripple[nr] = results[2] & 0x03; - printk("fscscy: writing value 0x%02x to fan%d_ripple\n", - data->fan_ripple[nr],nr); - fscscy_write_value(client,reg_ripple, - data->fan_ripple[nr]); - } - } -} - -void fscscy_wdog(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscscy_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscscy_update_client(client); - results[0] = data->watchdog[0] ; - results[1] = data->watchdog[1] & 0x02; - results[2] = data->watchdog[2] & 0xb0; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->watchdog[0] = results[0] & 0xff; - printk("fscscy: writing value 0x%02x to wdog_preset\n", - data->watchdog[0]); - fscscy_write_value(client,FSCSCY_REG_WDOG_PRESET, - data->watchdog[0]); - } - if (*nrels_mag >= 2) { - data->watchdog[1] = results[1] & 0x02; - printk("fscscy: writing value 0x%02x to wdog_state\n", - data->watchdog[1]); - fscscy_write_value(client,FSCSCY_REG_WDOG_STATE, - data->watchdog[1]); - } - if (*nrels_mag >= 3) { - data->watchdog[2] = results[2] & 0xb0; - printk("fscscy: writing value 0x%02x to wdog_control\n", - data->watchdog[2]); - fscscy_write_value(client,FSCSCY_REG_WDOG_CONTROL, - data->watchdog[2]); - } - } -} - -void fscscy_pciload(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscscy_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscscy_update_client(client); - results[0] = data->pciload; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - printk("fscscy: writing PCILOAD to chip not supported\n"); - } -} - -void fscscy_intrusion(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct fscscy_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - fscscy_update_client(client); - results[0] = data->intr_control & 0x80; - results[1] = data->intr_status & 0xc0; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->intr_control = results[0] & 0x80; - printk("fscscy: writing value 0x%02x to intr_control\n", - data->intr_control); - fscscy_write_value(client,FSCSCY_REG_INTR_CTRL, - data->intr_control); - } - } -} - -static int __init sm_fscscy_init(void) -{ - printk("fscscy.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&fscscy_driver); -} - -static void __exit sm_fscscy_exit(void) -{ - i2c_del_driver(&fscscy_driver); -} - - - -MODULE_AUTHOR - ("Martin Knoblauch based on work (fscpos) from Hermann Jung "); -MODULE_DESCRIPTION("fujitsu siemens scylla chip driver"); - -module_init(sm_fscscy_init); -module_exit(sm_fscscy_exit); diff --git a/kernel/chips/gl518sm.c b/kernel/chips/gl518sm.c deleted file mode 100644 index 28ab32f2..00000000 --- a/kernel/chips/gl518sm.c +++ /dev/null @@ -1,987 +0,0 @@ -/* - gl518sm.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard , - Kyösti Mälkki - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#ifdef __SMP__ -#include -#endif -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_2(gl518sm_r00, gl518sm_r80); - -/* Defining this will enable debug messages for the voltage iteration - code used with rev 0 ICs */ -#undef DEBUG_VIN - -/* Many GL518 constants specified below */ - -/* The GL518 registers */ -#define GL518_REG_CHIP_ID 0x00 -#define GL518_REG_REVISION 0x01 -#define GL518_REG_VENDOR_ID 0x02 -#define GL518_REG_CONF 0x03 -#define GL518_REG_TEMP 0x04 -#define GL518_REG_TEMP_OVER 0x05 -#define GL518_REG_TEMP_HYST 0x06 -#define GL518_REG_FAN_COUNT 0x07 -#define GL518_REG_FAN_LIMIT 0x08 -#define GL518_REG_VIN1_LIMIT 0x09 -#define GL518_REG_VIN2_LIMIT 0x0a -#define GL518_REG_VIN3_LIMIT 0x0b -#define GL518_REG_VDD_LIMIT 0x0c -#define GL518_REG_VIN3 0x0d -#define GL518_REG_MISC 0x0f -#define GL518_REG_ALARM 0x10 -#define GL518_REG_MASK 0x11 -#define GL518_REG_INT 0x12 -#define GL518_REG_VIN2 0x13 -#define GL518_REG_VIN1 0x14 -#define GL518_REG_VDD 0x15 - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-5:(val)+5) / 10)+119),\ - 0,255)) -#define TEMP_FROM_REG(val) (((val) - 119) * 10) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((960000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) \ - ( (val)==0 ? 0 : (val)==255 ? 0 : (960000/((val)*(div))) ) - -#define IN_TO_REG(val) (SENSORS_LIMIT((((val)*10+8)/19),0,255)) -#define IN_FROM_REG(val) (((val)*19)/10) - -#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*10+11)/23),0,255)) -#define VDD_FROM_REG(val) (((val)*23)/10) - -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) -#define DIV_FROM_REG(val) (1 << (val)) - -#define ALARMS_FROM_REG(val) val - -#define BEEP_ENABLE_TO_REG(val) ((val)?0:1) -#define BEEP_ENABLE_FROM_REG(val) ((val)?0:1) - -#define BEEPS_TO_REG(val) ((val) & 0x7f) -#define BEEPS_FROM_REG(val) ((val) & 0x7f) - -/* Each client has this additional data */ -struct gl518_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - - int iterate_lock; - int quit_thread; - struct task_struct *thread; - wait_queue_head_t wq; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - unsigned long last_updated_v00; - /* In jiffies (used only by rev00 chips) */ - - u8 voltage[4]; /* Register values; [0] = VDD */ - u8 voltage_min[4]; /* Register values; [0] = VDD */ - u8 voltage_max[4]; /* Register values; [0] = VDD */ - u8 iter_voltage[4]; /* Register values; [0] = VDD */ - u8 fan[2]; - u8 fan_min[2]; - u8 temp; /* Register values */ - u8 temp_over; /* Register values */ - u8 temp_hyst; /* Register values */ - u8 alarms, beeps; /* Register value */ - u8 alarm_mask; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u8 beep_enable; /* Boolean */ - u8 iterate; /* Voltage iteration mode */ -}; - -static int gl518_attach_adapter(struct i2c_adapter *adapter); -static int gl518_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void gl518_init_client(struct i2c_client *client); -static int gl518_detach_client(struct i2c_client *client); - -static int gl518_read_value(struct i2c_client *client, u8 reg); -static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value); -static void gl518_update_client(struct i2c_client *client); - -static void gl518_update_client_rev00(struct i2c_client *client); -static void gl518_update_iterate(struct i2c_client *client); - -static void gl518_vin(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_beep(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_fan1off(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_iterate(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* This is the driver that will be inserted */ -static struct i2c_driver gl518_driver = { - .name = "GL518SM sensor chip driver", - .id = I2C_DRIVERID_GL518, - .flags = I2C_DF_NOTIFY, - .attach_adapter = gl518_attach_adapter, - .detach_client = gl518_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define GL518_SYSCTL_VDD 1000 /* Volts * 100 */ -#define GL518_SYSCTL_VIN1 1001 -#define GL518_SYSCTL_VIN2 1002 -#define GL518_SYSCTL_VIN3 1003 -#define GL518_SYSCTL_FAN1 1101 /* RPM */ -#define GL518_SYSCTL_FAN2 1102 -#define GL518_SYSCTL_TEMP 1200 /* Degrees Celsius * 10 */ -#define GL518_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define GL518_SYSCTL_ALARMS 2001 /* bitvector */ -#define GL518_SYSCTL_BEEP 2002 /* bitvector */ -#define GL518_SYSCTL_FAN1OFF 2003 -#define GL518_SYSCTL_ITERATE 2004 - -#define GL518_ALARM_VDD 0x01 -#define GL518_ALARM_VIN1 0x02 -#define GL518_ALARM_VIN2 0x04 -#define GL518_ALARM_VIN3 0x08 -#define GL518_ALARM_TEMP 0x10 -#define GL518_ALARM_FAN1 0x20 -#define GL518_ALARM_FAN2 0x40 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected GL518. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table gl518_dir_table_template[] = { - {GL518_SYSCTL_VIN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_vin}, - {GL518_SYSCTL_VIN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_vin}, - {GL518_SYSCTL_VIN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_vin}, - {GL518_SYSCTL_VDD, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_vin}, - {GL518_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_fan}, - {GL518_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_fan}, - {GL518_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_temp}, - {GL518_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_fan_div}, - {GL518_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_alarms}, - {GL518_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_beep}, - {GL518_SYSCTL_FAN1OFF, "fan1off", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_fan1off}, - {GL518_SYSCTL_ITERATE, "iterate", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl518_iterate}, - {0} -}; - -/* I choose here for semi-static GL518SM allocation. Complete dynamic - allocation could also be used; the code needed for this would probably - take more memory than the datastructure takes now. */ -#define MAX_GL518_NR 4 -static struct i2c_client *gl518_list[MAX_GL518_NR]; - -static int gl518_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, gl518_detect); -} - -static int gl518_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct gl518_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("gl518sm.o: gl518_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access gl518_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct gl518_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &gl518_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if ( - (gl518_read_value(new_client, GL518_REG_CHIP_ID) != - 0x80) - || (gl518_read_value(new_client, GL518_REG_CONF) & - 0x80)) goto ERROR1; - } - - /* Determine the chip type. */ - if (kind <= 0) { - i = gl518_read_value(new_client, GL518_REG_REVISION); - if (i == 0x00) - kind = gl518sm_r00; - else if (i == 0x80) - kind = gl518sm_r80; - else { - if (kind == 0) - printk - ("gl518sm.o: Ignoring 'force' parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - goto ERROR1; - } - } - - type_name = "gl518sm"; - if (kind == gl518sm_r00) { - client_name = "GL518SM Revision 0x00 chip"; - } else if (kind == gl518sm_r80) { - client_name = "GL518SM Revision 0x80 chip"; - } else { -#ifdef DEBUG - printk("gl518sm.o: Internal error: unknown kind (%d)?!?", - kind); -#endif - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - - for (i = 0; i < MAX_GL518_NR; i++) - if (!gl518_list[i]) - break; - if (i == MAX_GL518_NR) { - printk - ("gl518sm.o: No empty slots left, recompile and heighten " - "MAX_GL518_NR!\n"); - err = -ENOMEM; - goto ERROR2; - } - gl518_list[i] = new_client; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry((struct i2c_client *) new_client, - type_name, - gl518_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the GL518SM chip */ - if (kind == gl518sm_r00) - data->iterate = 0; - else - data->iterate = 3; - data->iterate_lock = 0; - data->quit_thread = 0; - data->thread = NULL; - data->alarm_mask = 0xff; - data->voltage[0]=data->voltage[1]=data->voltage[2]=0; - gl518_init_client((struct i2c_client *) new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - for (i = 0; i < MAX_GL518_NR; i++) - if (new_client == gl518_list[i]) - gl518_list[i] = NULL; - ERROR2: - ERROR1: - kfree(data); - ERROR0: - return err; -} - - -/* Called when we have found a new GL518SM. */ -static void gl518_init_client(struct i2c_client *client) -{ - /* Power-on defaults (bit 7=1) */ - gl518_write_value(client, GL518_REG_CONF, 0x80); - - /* No noisy output (bit 2=1), Comparator mode (bit 3=0), two fans (bit4=0), - standby mode (bit6=0) */ - gl518_write_value(client, GL518_REG_CONF, 0x04); - - /* Never interrupts */ - gl518_write_value(client, GL518_REG_MASK, 0x00); - - /* Clear status register (bit 5=1), start (bit6=1) */ - gl518_write_value(client, GL518_REG_CONF, 0x24); - gl518_write_value(client, GL518_REG_CONF, 0x44); -} - -static int gl518_detach_client(struct i2c_client *client) -{ - int err, i; - struct gl518_data *data = client->data; - - i2c_deregister_entry(((struct gl518_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("gl518sm.o: Client deregistration failed, client not detached.\n"); - return err; - } - - for (i = 0; i < MAX_GL518_NR; i++) - if (client == gl518_list[i]) - break; - if ((i == MAX_GL518_NR)) { - printk("gl518sm.o: Client to detach not found.\n"); - return -ENOENT; - } - gl518_list[i] = NULL; - - if (data->thread) { - data->quit_thread = 1; - wake_up_interruptible(&data->wq); - } - - kfree(client->data); - - return 0; -} - - -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL518 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int gl518_read_value(struct i2c_client *client, u8 reg) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return swab16(i2c_smbus_read_word_data(client, reg)); - else - return i2c_smbus_read_byte_data(client, reg); -} - -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL518 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return i2c_smbus_write_word_data(client, reg, swab16(value)); - else - return i2c_smbus_write_byte_data(client, reg, value); -} - -static void gl518_update_client(struct i2c_client *client) -{ - struct gl518_data *data = client->data; - int val; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting gl518 update\n"); -#endif - - data->alarms = gl518_read_value(client, GL518_REG_INT); - data->beeps = gl518_read_value(client, GL518_REG_ALARM); - - val = gl518_read_value(client, GL518_REG_VDD_LIMIT); - data->voltage_min[0] = val & 0xff; - data->voltage_max[0] = (val >> 8) & 0xff; - val = gl518_read_value(client, GL518_REG_VIN1_LIMIT); - data->voltage_min[1] = val & 0xff; - data->voltage_max[1] = (val >> 8) & 0xff; - val = gl518_read_value(client, GL518_REG_VIN2_LIMIT); - data->voltage_min[2] = val & 0xff; - data->voltage_max[2] = (val >> 8) & 0xff; - val = gl518_read_value(client, GL518_REG_VIN3_LIMIT); - data->voltage_min[3] = val & 0xff; - data->voltage_max[3] = (val >> 8) & 0xff; - - val = gl518_read_value(client, GL518_REG_FAN_COUNT); - data->fan[0] = (val >> 8) & 0xff; - data->fan[1] = val & 0xff; - - val = gl518_read_value(client, GL518_REG_FAN_LIMIT); - data->fan_min[0] = (val >> 8) & 0xff; - data->fan_min[1] = val & 0xff; - - data->temp = gl518_read_value(client, GL518_REG_TEMP); - data->temp_over = - gl518_read_value(client, GL518_REG_TEMP_OVER); - data->temp_hyst = - gl518_read_value(client, GL518_REG_TEMP_HYST); - - val = gl518_read_value(client, GL518_REG_MISC); - data->fan_div[0] = (val >> 6) & 0x03; - data->fan_div[1] = (val >> 4) & 0x03; - - data->alarms &= data->alarm_mask; - - val = gl518_read_value(client, GL518_REG_CONF); - data->beep_enable = (val >> 2) & 1; - -#ifndef DEBUG_VIN - if (data->type != gl518sm_r00) { - data->voltage[0] = - gl518_read_value(client, GL518_REG_VDD); - data->voltage[1] = - gl518_read_value(client, GL518_REG_VIN1); - data->voltage[2] = - gl518_read_value(client, GL518_REG_VIN2); - data->voltage[3] = - gl518_read_value(client, GL518_REG_VIN3); - } else - gl518_update_client_rev00(client); -#else - gl518_update_client_rev00(client); -#endif - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -/* Here we decide how to run the iteration code. - When called, we trigger the iteration and report the last - measured voltage. No delay for user apps */ -static void gl518_update_client_rev00(struct i2c_client *client) -{ - struct gl518_data *data = client->data; - int i; - - if (data->iterate == 1) { /* 10 sec delay */ - /* as that update is slow, we consider the data valid for 30 seconds */ - if ( - ((jiffies - data->last_updated_v00 > 30 * HZ) - || (data->alarms & 7) - || (!data->valid)) && (!data->iterate_lock)) { - data->iterate_lock = 1; - gl518_update_iterate(client); - data->iterate_lock = 0; - } - for (i = 0; i < 4; i++) - data->voltage[i] = data->iter_voltage[i]; - } else if (data->iterate == 2) { /* show results of last iteration */ - for (i = 0; i < 4; i++) - data->voltage[i] = data->iter_voltage[i]; - wake_up_interruptible(&data->wq); - } else { /* no iteration */ - data->voltage[3] = - gl518_read_value(client, GL518_REG_VIN3); - } -} - -static int gl518_update_thread(void *c) -{ - struct i2c_client *client = c; - struct gl518_data *data = client->data; - -#ifdef __SMP__ - lock_kernel(); -#endif - exit_mm(current); - current->session = 1; - current->pgrp = 1; - sigfillset(¤t->blocked); - current->fs->umask = 0; - strcpy(current->comm, "gl518sm"); - - init_waitqueue_head(&(data->wq)); - data->thread = current; - -#ifdef __SMP__ - unlock_kernel(); -#endif - - for (;;) { - if (!data->iterate_lock) { - data->iterate_lock = 1; - gl518_update_iterate(client); - data->iterate_lock = 0; - } - - if ((data->quit_thread) || signal_pending(current)) - break; - interruptible_sleep_on(&data->wq); - } - - data->thread = NULL; - data->quit_thread = 0; - return 0; -} - -/* This updates vdd, vin1, vin2 values by doing slow and multiple - comparisons for the GL518SM rev 00 that lacks support for direct - reading of these values. Values are kept in iter_voltage */ - -static void gl518_update_iterate(struct i2c_client *client) -{ - struct gl518_data *data = client->data; - int i, j, loop_more = 1, min[3], max[3], delta[3]; - int alarm, beeps, irqs; - -#define VIN_REG(c) c==0?GL518_REG_VDD_LIMIT:\ - c==1?GL518_REG_VIN1_LIMIT:\ - GL518_REG_VIN2_LIMIT - - /* disable beeps & irqs for vin0-2 */ - beeps = gl518_read_value(client, GL518_REG_ALARM); - irqs = gl518_read_value(client, GL518_REG_MASK); - gl518_write_value(client, GL518_REG_ALARM, beeps & ~0x7); - gl518_write_value(client, GL518_REG_MASK, irqs & ~0x7); - - alarm = data->alarms; - - for (i = 0; i < 3; i++) { - if (alarm & (1 << i)) { - min[i] = 0; - max[i] = 127; - } else { - min[i] = data->voltage_min[i]; - max[i] = - (data->voltage_max[i] + - data->voltage_min[i]) / 2; - } - delta[i] = (max[i] - min[i]) / 2; - } - - for (j = 0; (j < 10 && loop_more); j++) { - - for (i = 0; i < 3; i++) - gl518_write_value(client, VIN_REG(i), - max[i] << 8 | min[i]); - - if ((data->thread) && - ((data->quit_thread) || signal_pending(current))) - goto finish; - - /* we wait now 1.5 seconds before comparing */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ + HZ / 2); - - alarm = gl518_read_value(client, GL518_REG_INT); - -#ifdef DEBUG_VIN - printk("gl518sm: iteration %2d: %4d%c %4d%c %4d%c\n", j, - max[0], (alarm & 1) ? '!' : ' ', - max[1], (alarm & 2) ? '!' : ' ', - max[2], (alarm & 4) ? '!' : ' '); -#endif - - for (loop_more = 0, i = 0; i < 3; i++) { - if (alarm & (1 << i)) - max[i] += delta[i]; - else - max[i] -= delta[i]; - - if (delta[i]) - loop_more++; - delta[i] >>= 1; - } - - } - - for (i = 0; i < 3; i++) - if (alarm & (1 << i)) - max[i]++; - -#ifdef DEBUG_VIN - printk("gl518sm: final :%5d %5d %5d\n", max[0], max[1], - max[2]); - printk("gl518sm: meter :%5d %5d %5d\n", data->voltage[0], - data->voltage[1], data->voltage[2]); -#endif - - /* update values, including vin3 */ - for (i = 0; i < 3; i++) { - data->iter_voltage[i] = max[i]; - } - data->iter_voltage[3] = gl518_read_value(client, GL518_REG_VIN3); - data->last_updated_v00 = jiffies; - - finish: - - /* reset values */ - for (i = 0; i < 3; i++) { - gl518_write_value(client, VIN_REG(i), - data->voltage_max[i] << 8 | data-> - voltage_min[i]); - } - - gl518_write_value(client, GL518_REG_ALARM, beeps); - gl518_write_value(client, GL518_REG_MASK, irqs); - -#undef VIN_REG -} - -void gl518_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - gl518_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over = TEMP_TO_REG(results[0]); - gl518_write_value(client, GL518_REG_TEMP_OVER, - data->temp_over); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - gl518_write_value(client, GL518_REG_TEMP_HYST, - data->temp_hyst); - } - } -} - -void gl518_vin(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - int nr = ctl_name - GL518_SYSCTL_VDD; - int regnr, old = 0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - gl518_update_client(client); - results[0] = nr ? IN_FROM_REG(data->voltage_min[nr]) : - VDD_FROM_REG(data->voltage_min[nr]); - results[1] = nr ? IN_FROM_REG(data->voltage_max[nr]) : - VDD_FROM_REG(data->voltage_max[nr]); - results[2] = nr ? IN_FROM_REG(data->voltage[nr]) : - VDD_FROM_REG(data->voltage[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - regnr = - nr == 0 ? GL518_REG_VDD_LIMIT : nr == - 1 ? GL518_REG_VIN1_LIMIT : nr == - 2 ? GL518_REG_VIN2_LIMIT : GL518_REG_VIN3_LIMIT; - if (*nrels_mag == 1) - old = gl518_read_value(client, regnr) & 0xff00; - if (*nrels_mag >= 2) { - data->voltage_max[nr] = - nr ? IN_TO_REG(results[1]) : - VDD_TO_REG(results[1]); - old = data->voltage_max[nr] << 8; - } - if (*nrels_mag >= 1) { - data->voltage_min[nr] = - nr ? IN_TO_REG(results[0]) : - VDD_TO_REG(results[0]); - old |= data->voltage_min[nr]; - gl518_write_value(client, regnr, old); - } - } -} - - -void gl518_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - int nr = ctl_name - GL518_SYSCTL_FAN1; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl518_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - results[1] = - FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr] = FAN_TO_REG(results[0], - DIV_FROM_REG(data-> - fan_div - [nr])); - old = - gl518_read_value(client, GL518_REG_FAN_LIMIT); - - if (nr == 0) { - old = - (old & 0x00ff) | (data-> - fan_min[0] << 8); - if (results[0] == 0) - data->alarm_mask &= ~0x20; - else - data->alarm_mask |= 0x20; - } else { - old = (old & 0xff00) | data->fan_min[1]; - if (results[0] == 0) - data->alarm_mask &= ~0x40; - else - data->alarm_mask |= 0x40; - } - gl518_write_value(client, GL518_REG_FAN_LIMIT, - old); - } - } -} - - -void gl518_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl518_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void gl518_beep(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl518_update_client(client); - results[0] = BEEP_ENABLE_FROM_REG(data->beep_enable); - results[1] = BEEPS_FROM_REG(data->beeps); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->beep_enable = BEEP_ENABLE_TO_REG(results[0]); - gl518_write_value(client, GL518_REG_CONF, - (gl518_read_value(client, - GL518_REG_CONF) - & 0xfb) | (data-> - beep_enable << 2)); - } - if (*nrels_mag >= 2) { - data->beeps = - BEEPS_TO_REG(results[1]) & data->alarm_mask; - gl518_write_value(client, GL518_REG_ALARM, - data->beeps); - } - } -} - - -void gl518_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - int old; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl518_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = gl518_read_value(client, GL518_REG_MISC); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0xcf) | (data->fan_div[1] << 4); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0x3f) | (data->fan_div[0] << 6); - } - gl518_write_value(client, GL518_REG_MISC, old); - } -} - -void gl518_fan1off(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int old; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = - ((gl518_read_value(client, GL518_REG_MISC) & 0x08) != - 0); - results[1] = - ((gl518_read_value(client, GL518_REG_CONF) & 0x10) != - 0); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - old = - gl518_read_value(client, - GL518_REG_MISC) & 0xf7; - if (results[0]) - old |= 0x08; - gl518_write_value(client, GL518_REG_MISC, old); - } - if (*nrels_mag >= 2) { - old = - gl518_read_value(client, - GL518_REG_CONF) & 0xef; - if (results[1]) - old |= 0x10; - gl518_write_value(client, GL518_REG_CONF, old); - } - } -} - -void gl518_iterate(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - int i; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->iterate; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE && - data->type == gl518sm_r00 ) { - if ((*nrels_mag >= 1) && (data->iterate != results[0])) { - data->iterate = results[0]; - for (i = 0; i < 4; i++) { - data->voltage[i] = 0; - data->iter_voltage[i] = 0; - } - data->valid = 0; - - if ((data->iterate != 2) && (data->thread)) { - data->quit_thread = 1; - wake_up_interruptible(&data->wq); - } else if ((data->iterate == 2) && (!data->thread)) { - init_waitqueue_head(&(data->wq)); - kernel_thread(gl518_update_thread, - (void *) client, 0); - } - } - } -} - -static int __init sm_gl518sm_init(void) -{ - printk("gl518sm.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&gl518_driver); -} - -static void __exit sm_gl518sm_exit(void) -{ - i2c_del_driver(&gl518_driver); -} - - - -MODULE_AUTHOR - ("Frodo Looijaard and Kyösti Mälkki "); -MODULE_DESCRIPTION("GL518SM driver"); - -module_init(sm_gl518sm_init); -module_exit(sm_gl518sm_exit); diff --git a/kernel/chips/gl520sm.c b/kernel/chips/gl520sm.c deleted file mode 100644 index 39e703c3..00000000 --- a/kernel/chips/gl520sm.c +++ /dev/null @@ -1,804 +0,0 @@ -/* - gl520sm.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard , - Kyösti Mälkki - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(gl520sm); - -/* Many GL520 constants specified below -One of the inputs can be configured as either temp or voltage. -That's why _TEMP2 and _VIN4 access the same register -*/ - -/* The GL520 registers */ -#define GL520_REG_CHIP_ID 0x00 -#define GL520_REG_REVISION 0x01 -#define GL520_REG_VID 0x02 -#define GL520_REG_CONF 0x03 -#define GL520_REG_TEMP1 0x04 -#define GL520_REG_TEMP1_OVER 0x05 -#define GL520_REG_TEMP1_HYST 0x06 -#define GL520_REG_FAN_COUNT 0x07 -#define GL520_REG_FAN_LIMIT 0x08 -#define GL520_REG_VIN1_LIMIT 0x09 -#define GL520_REG_VIN2_LIMIT 0x0a -#define GL520_REG_VIN3_LIMIT 0x0b -#define GL520_REG_VDD_LIMIT 0x0c -#define GL520_REG_VIN3 0x0d -#define GL520_REG_VIN4 0x0e -#define GL520_REG_TEMP2 0x0e -#define GL520_REG_MISC 0x0f -#define GL520_REG_ALARM 0x10 -#define GL520_REG_MASK 0x11 -#define GL520_REG_INT 0x12 -#define GL520_REG_VIN2 0x13 -#define GL520_REG_VIN1 0x14 -#define GL520_REG_VDD 0x15 -#define GL520_REG_TEMP2_OVER 0x17 -#define GL520_REG_VIN4_MAX 0x17 -#define GL520_REG_TEMP2_HYST 0x18 -#define GL520_REG_VIN4_MIN 0x18 - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-5:(val)+5) / 10)+130),\ - 0,255)) -#define TEMP_FROM_REG(val) (((val) - 130) * 10) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((960000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) \ - ( (val)==0 ? 0 : (val)==255 ? 0 : (960000/((val)*(div))) ) - -#define IN_TO_REG(val) (SENSORS_LIMIT((((val)*10+8)/19),0,255)) -#define IN_FROM_REG(val) (((val)*19)/10) - -#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*10+11)/23),0,255)) -#define VDD_FROM_REG(val) (((val)*23)/10) - -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) -#define DIV_FROM_REG(val) (1 << (val)) - -#define ALARMS_FROM_REG(val) val - -#define BEEP_ENABLE_TO_REG(val) ((val)?0:1) -#define BEEP_ENABLE_FROM_REG(val) ((val)?0:1) - -#define BEEPS_TO_REG(val) (val) -#define BEEPS_FROM_REG(val) (val) - -#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ - 205-(val)*5) - -/* Each client has this additional data */ -struct gl520_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 voltage[5]; /* Register values; [0] = VDD */ - u8 voltage_min[5]; /* Register values; [0] = VDD */ - u8 voltage_max[5]; /* Register values; [0] = VDD */ - u8 fan[2]; - u8 fan_min[2]; - u8 temp[2]; /* Register values */ - u8 temp_over[2]; /* Register values */ - u8 temp_hyst[2]; /* Register values */ - u8 alarms, beeps, vid; /* Register value */ - u8 alarm_mask; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u8 beep_enable; /* Boolean */ - u8 two_temps; /* Boolean */ -}; - -static int gl520_attach_adapter(struct i2c_adapter *adapter); -static int gl520_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void gl520_init_client(struct i2c_client *client); -static int gl520_detach_client(struct i2c_client *client); - -static int gl520_read_value(struct i2c_client *client, u8 reg); -static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value); -static void gl520_update_client(struct i2c_client *client); - -static void gl520_vin(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl520_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl520_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl520_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl520_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl520_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl520_beep(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl520_fan1off(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl520_config(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* This is the driver that will be inserted */ -static struct i2c_driver gl520_driver = { - .name = "GL520SM sensor chip driver", - .id = I2C_DRIVERID_GL520, - .flags = I2C_DF_NOTIFY, - .attach_adapter = gl520_attach_adapter, - .detach_client = gl520_detach_client, -}; -/* -- SENSORS SYSCTL START -- */ - -#define GL520_SYSCTL_VDD 1000 /* Volts * 100 */ -#define GL520_SYSCTL_VIN1 1001 -#define GL520_SYSCTL_VIN2 1002 -#define GL520_SYSCTL_VIN3 1003 -#define GL520_SYSCTL_VIN4 1004 -#define GL520_SYSCTL_FAN1 1101 /* RPM */ -#define GL520_SYSCTL_FAN2 1102 -#define GL520_SYSCTL_TEMP1 1200 /* Degrees Celsius * 10 */ -#define GL520_SYSCTL_TEMP2 1201 /* Degrees Celsius * 10 */ -#define GL520_SYSCTL_VID 1300 -#define GL520_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define GL520_SYSCTL_ALARMS 2001 /* bitvector */ -#define GL520_SYSCTL_BEEP 2002 /* bitvector */ -#define GL520_SYSCTL_FAN1OFF 2003 -#define GL520_SYSCTL_CONFIG 2004 - -#define GL520_ALARM_VDD 0x01 -#define GL520_ALARM_VIN1 0x02 -#define GL520_ALARM_VIN2 0x04 -#define GL520_ALARM_VIN3 0x08 -#define GL520_ALARM_TEMP1 0x10 -#define GL520_ALARM_FAN1 0x20 -#define GL520_ALARM_FAN2 0x40 -#define GL520_ALARM_TEMP2 0x80 -#define GL520_ALARM_VIN4 0x80 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected GL520. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table gl520_dir_table_template[] = { - {GL520_SYSCTL_VIN1, "vin1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_vin}, - {GL520_SYSCTL_VIN2, "vin2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_vin}, - {GL520_SYSCTL_VIN3, "vin3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_vin}, - {GL520_SYSCTL_VIN4, "vin4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_vin}, - {GL520_SYSCTL_VDD, "vdd", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_vin}, - {GL520_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_vid}, - {GL520_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_fan}, - {GL520_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_fan}, - {GL520_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_temp}, - {GL520_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_temp}, - {GL520_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_fan_div}, - {GL520_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_alarms}, - {GL520_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_beep}, - {GL520_SYSCTL_FAN1OFF, "fan1off", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_fan1off}, - {GL520_SYSCTL_CONFIG, "config", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &gl520_config}, - {0} -}; - -static int gl520_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, gl520_detect); -} - -static int gl520_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct gl520_data *data; - int err = 0; - const char *type_name = ""; - char client_name[32]; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("gl520sm.o: gl520_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access gl520_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct gl520_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &gl520_driver; - new_client->flags = 0; - - /* Determine the chip type. */ - - if (gl520_read_value(new_client, GL520_REG_CHIP_ID) != 0x20) { - printk - ("gl520sm.o: Ignoring 'force' parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - goto ERROR1; - } else { - kind = gl520sm; - } - - i = gl520_read_value(new_client, GL520_REG_REVISION); - if (kind == gl520sm) { - type_name = "gl520sm"; - sprintf(client_name, "GL520SM Revision %02x chip", i); - } else { -#ifdef DEBUG - printk("gl520sm.o: Internal error: unknown kind (%d)?!?", - kind); -#endif - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - gl520_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the GL520SM chip */ - data->alarm_mask = 0xff; - gl520_init_client(new_client); - if (data->two_temps) - data->voltage_max[4] = data->voltage_min[4] = - data->voltage[4] = 0; - else - data->temp_hyst[1] = data->temp_over[1] = - data->temp[1] = 0; - - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - - -/* Called when we have found a new GL520SM. */ -static void gl520_init_client(struct i2c_client *client) -{ - struct gl520_data *data = (struct gl520_data *)(client->data); - u8 oldconf, conf; - - conf = oldconf = gl520_read_value(client, GL520_REG_CONF); - data->two_temps = !(conf & 0x10); - - /* If IRQ# is disabled, we can safely force comparator mode */ - if (!(conf & 0x20)) - conf &= 0xf7; - - /* Enable monitoring if needed */ - conf |= 0x40; - - if (conf != oldconf) - gl520_write_value(client, GL520_REG_CONF, conf); -} - -static int gl520_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct gl520_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("gl520sm.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - - -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL520 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int gl520_read_value(struct i2c_client *client, u8 reg) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return swab16(i2c_smbus_read_word_data(client, reg)); - else - return i2c_smbus_read_byte_data(client, reg); -} - -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL520 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return i2c_smbus_write_word_data(client, reg, swab16(value)); - else - return i2c_smbus_write_byte_data(client, reg, value); -} - -static void gl520_update_client(struct i2c_client *client) -{ - struct gl520_data *data = client->data; - int val; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting gl520 update\n"); -#endif - - data->alarms = gl520_read_value(client, GL520_REG_INT); - data->beeps = gl520_read_value(client, GL520_REG_ALARM); - data->vid = gl520_read_value(client, GL520_REG_VID) & 0x1f; - - val = gl520_read_value(client, GL520_REG_VDD_LIMIT); - data->voltage_min[0] = val & 0xff; - data->voltage_max[0] = (val >> 8) & 0xff; - val = gl520_read_value(client, GL520_REG_VIN1_LIMIT); - data->voltage_min[1] = val & 0xff; - data->voltage_max[1] = (val >> 8) & 0xff; - val = gl520_read_value(client, GL520_REG_VIN2_LIMIT); - data->voltage_min[2] = val & 0xff; - data->voltage_max[2] = (val >> 8) & 0xff; - val = gl520_read_value(client, GL520_REG_VIN3_LIMIT); - data->voltage_min[3] = val & 0xff; - data->voltage_max[3] = (val >> 8) & 0xff; - - val = gl520_read_value(client, GL520_REG_FAN_COUNT); - data->fan[0] = (val >> 8) & 0xff; - data->fan[1] = val & 0xff; - - val = gl520_read_value(client, GL520_REG_FAN_LIMIT); - data->fan_min[0] = (val >> 8) & 0xff; - data->fan_min[1] = val & 0xff; - - data->temp[0] = gl520_read_value(client, GL520_REG_TEMP1); - data->temp_over[0] = - gl520_read_value(client, GL520_REG_TEMP1_OVER); - data->temp_hyst[0] = - gl520_read_value(client, GL520_REG_TEMP1_HYST); - - val = gl520_read_value(client, GL520_REG_MISC); - data->fan_div[0] = (val >> 6) & 0x03; - data->fan_div[1] = (val >> 4) & 0x03; - - data->alarms &= data->alarm_mask; - - val = gl520_read_value(client, GL520_REG_CONF); - data->beep_enable = (val >> 2) & 1; - - data->voltage[0] = gl520_read_value(client, GL520_REG_VDD); - data->voltage[1] = - gl520_read_value(client, GL520_REG_VIN1); - data->voltage[2] = - gl520_read_value(client, GL520_REG_VIN2); - data->voltage[3] = - gl520_read_value(client, GL520_REG_VIN3); - - /* Temp1 and Vin4 are the same input */ - if (data->two_temps) { - data->temp[1] = - gl520_read_value(client, GL520_REG_TEMP2); - data->temp_over[1] = - gl520_read_value(client, GL520_REG_TEMP2_OVER); - data->temp_hyst[1] = - gl520_read_value(client, GL520_REG_TEMP2_HYST); - } else { - data->voltage[4] = - gl520_read_value(client, GL520_REG_VIN4); - data->voltage_min[4] = - gl520_read_value(client, GL520_REG_VIN4_MIN); - data->voltage_max[4] = - gl520_read_value(client, GL520_REG_VIN4_MAX); - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -void gl520_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl520_data *data = client->data; - int nr = ctl_name - GL520_SYSCTL_TEMP1; - int regnr; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - gl520_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over[nr]); - results[1] = TEMP_FROM_REG(data->temp_hyst[nr]); - results[2] = TEMP_FROM_REG(data->temp[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if ((nr == 1) && (!data->two_temps)) - return; - regnr = - nr == 0 ? GL520_REG_TEMP1_OVER : GL520_REG_TEMP2_OVER; - if (*nrels_mag >= 1) { - data->temp_over[nr] = TEMP_TO_REG(results[0]); - gl520_write_value(client, regnr, - data->temp_over[nr]); - } - regnr = - nr == 0 ? GL520_REG_TEMP1_HYST : GL520_REG_TEMP2_HYST; - if (*nrels_mag >= 2) { - data->temp_hyst[nr] = TEMP_TO_REG(results[1]); - gl520_write_value(client, regnr, - data->temp_hyst[nr]); - } - } -} - -void gl520_vin(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl520_data *data = client->data; - int nr = ctl_name - GL520_SYSCTL_VDD; - int regnr, old = 0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - gl520_update_client(client); - results[0] = nr ? IN_FROM_REG(data->voltage_min[nr]) : - VDD_FROM_REG(data->voltage_min[nr]); - results[1] = nr ? IN_FROM_REG(data->voltage_max[nr]) : - VDD_FROM_REG(data->voltage_max[nr]); - results[2] = nr ? IN_FROM_REG(data->voltage[nr]) : - VDD_FROM_REG(data->voltage[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (nr != 4) { - regnr = - nr == 0 ? GL520_REG_VDD_LIMIT : nr == - 1 ? GL520_REG_VIN1_LIMIT : nr == - 2 ? GL520_REG_VIN2_LIMIT : - GL520_REG_VIN3_LIMIT; - if (*nrels_mag == 1) - old = - gl520_read_value(client, - regnr) & 0xff00; - if (*nrels_mag >= 2) { - data->voltage_max[nr] = - nr ? IN_TO_REG(results[1]) : - VDD_TO_REG(results[1]); - old = data->voltage_max[nr] << 8; - } - if (*nrels_mag >= 1) { - data->voltage_min[nr] = - nr ? IN_TO_REG(results[0]) : - VDD_TO_REG(results[0]); - old |= data->voltage_min[nr]; - gl520_write_value(client, regnr, old); - } - } else if (!data->two_temps) { - if (*nrels_mag == 1) - gl520_write_value(client, - GL520_REG_VIN4_MIN, - IN_TO_REG(results[0])); - if (*nrels_mag >= 2) - gl520_write_value(client, - GL520_REG_VIN4_MAX, - IN_TO_REG(results[1])); - } - } -} - - -void gl520_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl520_data *data = client->data; - int nr = ctl_name - GL520_SYSCTL_FAN1; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl520_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - results[1] = - FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr] = FAN_TO_REG(results[0], - DIV_FROM_REG(data-> - fan_div - [nr])); - old = - gl520_read_value(client, GL520_REG_FAN_LIMIT); - - if (nr == 0) { - old = - (old & 0x00ff) | (data-> - fan_min[nr] << 8); - if (results[0] == 0) - data->alarm_mask &= ~0x20; - else - data->alarm_mask |= 0x20; - } else { - old = (old & 0xff00) | data->fan_min[nr]; - if (results[0] == 0) - data->alarm_mask &= ~0x40; - else - data->alarm_mask |= 0x40; - } - gl520_write_value(client, GL520_REG_FAN_LIMIT, - old); - } - } -} - - -void gl520_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl520_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl520_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void gl520_beep(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl520_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl520_update_client(client); - results[0] = BEEP_ENABLE_FROM_REG(data->beep_enable); - results[1] = BEEPS_FROM_REG(data->beeps); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->beep_enable = BEEP_ENABLE_TO_REG(results[0]); - gl520_write_value(client, GL520_REG_CONF, - (gl520_read_value(client, - GL520_REG_CONF) - & 0xfb) | (data-> - beep_enable << 2)); - } - if (*nrels_mag >= 2) { - data->beeps = - BEEPS_TO_REG(results[1]) & data->alarm_mask; - gl520_write_value(client, GL520_REG_ALARM, - data->beeps); - } - } -} - - -void gl520_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl520_data *data = client->data; - int old; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl520_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = gl520_read_value(client, GL520_REG_MISC); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0xcf) | (data->fan_div[1] << 4); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0x3f) | (data->fan_div[0] << 6); - } - gl520_write_value(client, GL520_REG_MISC, old); - } -} - -void gl520_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl520_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - gl520_update_client(client); - results[0] = VID_FROM_REG(data->vid); - *nrels_mag = 1; - } -} - -void gl520_fan1off(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int old; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = - ((gl520_read_value(client, GL520_REG_MISC) & 0x04) != - 0); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - old = - gl520_read_value(client, - GL520_REG_MISC) & 0xfb; - if (results[0]) - old |= 0x04; - gl520_write_value(client, GL520_REG_MISC, old); - } - } -} - -void gl520_config(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl520_data *data = client->data; - int old; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = - ((gl520_read_value(client, GL520_REG_CONF) & 0x10) == - 0); - data->two_temps = results[0]; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - old = - gl520_read_value(client, - GL520_REG_CONF) & 0xef; - if (!results[1]) { - old |= 0x10; - data->two_temps = 0; - data->temp_hyst[1] = data->temp_over[1] = - data->temp[1] = 0; - } else { - data->two_temps = 1; - data->voltage_max[4] = data->voltage_min[4] = - data->voltage[4] = 0; - } - gl520_write_value(client, GL520_REG_CONF, old); - } - } -} - -static int __init sm_gl520sm_init(void) -{ - printk("gl520sm.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&gl520_driver); -} - -static void __exit sm_gl520sm_exit(void) -{ - i2c_del_driver(&gl520_driver); -} - - - -MODULE_AUTHOR - ("Frodo Looijaard and Kyösti Mälkki "); -MODULE_DESCRIPTION("GL520SM driver"); - -module_init(sm_gl520sm_init); -module_exit(sm_gl520sm_exit); diff --git a/kernel/chips/it87.c b/kernel/chips/it87.c deleted file mode 100644 index 01286a7e..00000000 --- a/kernel/chips/it87.c +++ /dev/null @@ -1,1130 +0,0 @@ -/* - it87.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring. - - Supports: IT8705F Super I/O chip w/LPC interface - IT8712F Super I/O chip w/LPC interface & SMBus - SiS950 A clone of the IT8705F - - Copyright (c) 2001 Chris Gauthron - Largely inspired by lm78.c of the same package - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - djg@pdp8.net David Gesswein 7/18/01 - Modified to fix bug with not all alarms enabled. - Added ability to read battery voltage and select temperature sensor - type at module load time. -*/ - -/* - michael.hufer@gmx.de Michael Hufer 09/07/03 - Modified configure (enable/disable) chip reset at module load time. - Added ability to read and set fan pwm registers and the smart - guardian (sg) features of the chip. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x28, 0x2f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0x0290, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_2(it87, it8712); - - -#define REG 0x2e /* The register to read/write */ -#define DEV 0x07 /* Register: Logical device select */ -#define VAL 0x2f /* The value to read/write */ -#define PME 0x04 /* The device with the fan registers in it */ -#define DEVID 0x20 /* Register: Device ID */ -#define DEVREV 0x22 /* Register: Device Revision */ - -static inline int -superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -static int superio_inw(int reg) -{ - int val; - outb(reg++, REG); - val = inb(VAL) << 8; - outb(reg, REG); - val |= inb(VAL); - return val; -} - -static inline void -superio_select(void) -{ - outb(DEV, REG); - outb(PME, VAL); -} - -static inline void -superio_enter(void) -{ - outb(0x87, REG); - outb(0x01, REG); - outb(0x55, REG); - outb(0x55, REG); -} - -static inline void -superio_exit(void) -{ - outb(0x02, REG); - outb(0x02, VAL); -} - -#define IT87_DEVID_MATCH(id) ((id) == 0x8712 || (id) == 0x8705) - -#define IT87_ACT_REG 0x30 -#define IT87_BASE_REG 0x60 - -/* Update battery voltage after every reading if true */ -static int update_vbat = 0; - -/* Reset the registers on init */ -static int reset = 0; - -/* Many IT87 constants specified below */ - -/* Length of ISA address segment */ -#define IT87_EXTENT 8 - -/* Where are the ISA address/data registers relative to the base address */ -#define IT87_ADDR_REG_OFFSET 5 -#define IT87_DATA_REG_OFFSET 6 - -/*----- The IT87 registers -----*/ - -#define IT87_REG_CONFIG 0x00 - -#define IT87_REG_ALARM1 0x01 -#define IT87_REG_ALARM2 0x02 -#define IT87_REG_ALARM3 0x03 - -#define IT87_REG_VID 0x0a -#define IT87_REG_FAN_DIV 0x0b - -#define IT87_REG_FAN(nr) (0x0c + (nr)) -#define IT87_REG_FAN_MIN(nr) (0x0f + (nr)) -#define IT87_REG_FAN_CTRL 0x13 - -/* pwm and smart guardian registers */ - -#define IT87_REG_FAN_ONOFF 0x14 -#define IT87_REG_PWM(nr) (0x14 + (nr)) -#define IT87_REG_SG_TL_OFF(nr) (0x58 + (nr)*8) -#define IT87_REG_SG_TL_LOW(nr) (0x59 + (nr)*8) -#define IT87_REG_SG_TL_MED(nr) (0x5a + (nr)*8) -#define IT87_REG_SG_TL_HI(nr) (0x5b + (nr)*8) -#define IT87_REG_SG_TL_OVR(nr) (0x5c + (nr)*8) -#define IT87_REG_SG_PWM_LOW(nr) (0x5d + (nr)*8) -#define IT87_REG_SG_PWM_MED(nr) (0x5e + (nr)*8) -#define IT87_REG_SG_PWM_HI(nr) (0x5f + (nr)*8) - -/* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */ - -#define IT87_REG_VIN(nr) (0x20 + (nr)) -#define IT87_REG_TEMP(nr) (0x28 + (nr)) - -#define IT87_REG_VIN_MAX(nr) (0x30 + (nr) * 2) -#define IT87_REG_VIN_MIN(nr) (0x31 + (nr) * 2) -#define IT87_REG_TEMP_HIGH(nr) (0x3e + (nr) * 2) -#define IT87_REG_TEMP_LOW(nr) (0x3f + (nr) * 2) - -#define IT87_REG_I2C_ADDR 0x48 - -#define IT87_REG_VIN_ENABLE 0x50 -#define IT87_REG_TEMP_ENABLE 0x51 - -#define IT87_REG_CHIPID 0x58 -#define IT87_REG_CHIPID2 0x5b /* IT8712F only */ - -/* sensor pin types */ -#define UNUSED 0 -#define THERMISTOR 2 -#define PIIDIODE 3 - -/* Conversions. Limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) -#define IN_FROM_REG(val) (((val) * 16 + 5) / 10) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) - -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-5)/10):\ - ((val)+5)/10),-127,127)) -#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10) - -#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ - 205-(val)*5) -#define ALARMS_FROM_REG(val) (val) - -extern inline u8 DIV_TO_REG(long val) -{ - u8 i; - for( i = 0; i <= 7; i++ ) - { - if( val>>i == 1 ) - return i; - } - return 1; -} -#define DIV_FROM_REG(val) (1 << (val)) - -/* For each registered IT87, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new it87 client is - allocated. */ -struct it87_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[9]; /* Register value */ - u8 in_max[9]; /* Register value */ - u8 in_min[9]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 temp[3]; /* Register value */ - u8 temp_high[3]; /* Register value */ - u8 temp_low[3]; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ - u32 alarms; /* Register encoding, combined */ - u8 pwm[3]; /* Register value */ - u8 fan_ctl[2]; /* Register encoding */ - u8 sg_tl[3][5]; /* Register value */ - u8 sg_pwm[3][3]; /* Register value */ - u8 sens[3]; /* 2 = Thermistor, - 3 = PII/Celeron diode */ -}; - - -static int it87_attach_adapter(struct i2c_adapter *adapter); -static int it87_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int it87_detach_client(struct i2c_client *client); - -static int it87_read_value(struct i2c_client *client, u8 register); -static int it87_write_value(struct i2c_client *client, u8 register, - u8 value); -static void it87_update_client(struct i2c_client *client); -static void it87_init_client(struct i2c_client *client); - - -static void it87_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void it87_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void it87_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void it87_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void it87_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void it87_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void it87_fan_ctl(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void it87_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void it87_sgpwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void it87_sgtl(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void it87_sens(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver it87_driver = { - .name = "IT87xx sensor driver", - .id = I2C_DRIVERID_IT87, - .flags = I2C_DF_NOTIFY, - .attach_adapter = it87_attach_adapter, - .detach_client = it87_detach_client, -}; - -/* The /proc/sys entries */ - -/* -- SENSORS SYSCTL START -- */ -#define IT87_SYSCTL_IN0 1000 /* Volts * 100 */ -#define IT87_SYSCTL_IN1 1001 -#define IT87_SYSCTL_IN2 1002 -#define IT87_SYSCTL_IN3 1003 -#define IT87_SYSCTL_IN4 1004 -#define IT87_SYSCTL_IN5 1005 -#define IT87_SYSCTL_IN6 1006 -#define IT87_SYSCTL_IN7 1007 -#define IT87_SYSCTL_IN8 1008 -#define IT87_SYSCTL_FAN1 1101 /* Rotations/min */ -#define IT87_SYSCTL_FAN2 1102 -#define IT87_SYSCTL_FAN3 1103 -#define IT87_SYSCTL_TEMP1 1200 /* Degrees Celsius * 10 */ -#define IT87_SYSCTL_TEMP2 1201 /* Degrees Celsius * 10 */ -#define IT87_SYSCTL_TEMP3 1202 /* Degrees Celsius * 10 */ -#define IT87_SYSCTL_VID 1300 /* Volts * 100 */ -#define IT87_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define IT87_SYSCTL_ALARMS 2004 /* bitvector */ - -#define IT87_SYSCTL_PWM1 1401 -#define IT87_SYSCTL_PWM2 1402 -#define IT87_SYSCTL_PWM3 1403 -#define IT87_SYSCTL_FAN_CTL 1501 -#define IT87_SYSCTL_FAN_ON_OFF 1502 -#define IT87_SYSCTL_SENS1 1601 /* 1, 2, or Beta (3000-5000) */ -#define IT87_SYSCTL_SENS2 1602 -#define IT87_SYSCTL_SENS3 1603 - -#define IT87_ALARM_IN0 0x000100 -#define IT87_ALARM_IN1 0x000200 -#define IT87_ALARM_IN2 0x000400 -#define IT87_ALARM_IN3 0x000800 -#define IT87_ALARM_IN4 0x001000 -#define IT87_ALARM_IN5 0x002000 -#define IT87_ALARM_IN6 0x004000 -#define IT87_ALARM_IN7 0x008000 -#define IT87_ALARM_FAN1 0x0001 -#define IT87_ALARM_FAN2 0x0002 -#define IT87_ALARM_FAN3 0x0004 -#define IT87_ALARM_TEMP1 0x00010000 -#define IT87_ALARM_TEMP2 0x00020000 -#define IT87_ALARM_TEMP3 0x00040000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected IT87. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table it87_dir_table_template[] = { - {IT87_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_in}, - {IT87_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_in}, - {IT87_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_in}, - {IT87_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_in}, - {IT87_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_in}, - {IT87_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_in}, - {IT87_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_in}, - {IT87_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_in}, - {IT87_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_in}, - {IT87_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_fan}, - {IT87_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_fan}, - {IT87_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_fan}, - {IT87_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_temp}, - {IT87_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_temp}, - {IT87_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_temp}, - {IT87_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_vid}, - {IT87_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_fan_div}, - {IT87_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_alarms}, - {IT87_SYSCTL_FAN_CTL, "fan_ctl", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_fan_ctl}, - {IT87_SYSCTL_FAN_ON_OFF, "fan_on_off", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_fan_ctl}, - {IT87_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_pwm}, - {IT87_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_pwm}, - {IT87_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_pwm}, - {IT87_SYSCTL_PWM1, "sg_pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_sgpwm}, - {IT87_SYSCTL_PWM2, "sg_pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_sgpwm}, - {IT87_SYSCTL_PWM3, "sg_pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_sgpwm}, - {IT87_SYSCTL_PWM1, "sg_tl1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_sgtl}, - {IT87_SYSCTL_PWM2, "sg_tl2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_sgtl}, - {IT87_SYSCTL_PWM3, "sg_tl3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_sgtl}, - {IT87_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_sens}, - {IT87_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_sens}, - {IT87_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &it87_sens}, - {0} -}; - - -/* This function is called when: - * it87_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and it87_driver is still present) */ -static int it87_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, it87_detect); -} - -static int __init it87_find(int *address) -{ - int err = -ENODEV; - u16 devid; - - superio_enter(); - devid = superio_inw(DEVID); - if (!IT87_DEVID_MATCH(devid)) - goto exit; - - superio_select(); - if (!(superio_inb(IT87_ACT_REG) & 0x01)) { - printk(KERN_INFO "it87: Device not activated, skipping\n"); - goto exit; - } - - *address = superio_inw(IT87_BASE_REG) & ~(IT87_EXTENT - 1); - if (*address == 0) { - printk(KERN_INFO "it87: Base address not set, skipping\n"); - goto exit; - } - - err = 0; - printk(KERN_INFO "it87: Found IT%04xF chip at 0x%x, revision %d\n", - devid, *address, superio_inb(DEVREV) & 0x0f); - -exit: - superio_exit(); - return err; -} - -/* This function is called by i2c_detect */ -static int it87_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct it87_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - int is_isa = i2c_is_isa_adapter(adapter); - - if (!is_isa - && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - if (is_isa - && check_region(address, IT87_EXTENT)) - return 0; - - /* Probe whether there is anything available on this address. Already - done for SMBus clients */ - if (is_isa && kind < 0) { -#define REALLY_SLOW_IO - /* We need the timeouts for at least some IT87-like chips. - But only if we read 'undefined' registers. */ - i = inb_p(address + 1); - if (inb_p(address + 2) != i - || inb_p(address + 3) != i - || inb_p(address + 7) != i) - return 0; -#undef REALLY_SLOW_IO - - /* Let's just hope nothing breaks here */ - i = inb_p(address + 5) & 0x7f; - outb_p(~i & 0x7f, address + 5); - if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { - outb_p(i, address + 5); - return 0; - } - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access it87_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct it87_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - if (is_isa) - init_MUTEX(&data->lock); - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &it87_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if ((it87_read_value(new_client, IT87_REG_CONFIG) & 0x80) - || (!is_isa - && it87_read_value(new_client, IT87_REG_I2C_ADDR) != address)) - goto ERROR1; - } - - /* Determine the chip type. */ - if (kind <= 0) { - i = it87_read_value(new_client, IT87_REG_CHIPID); - if (i == 0x90) { - kind = it87; - i = it87_read_value(new_client, IT87_REG_CHIPID2); - if (i == 0x12) - kind = it8712; - } - else { - if (kind == 0) - printk - ("it87.o: Ignoring 'force' parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - goto ERROR1; - } - } - - if (kind == it87) { - type_name = "it87"; - client_name = "IT87 chip"; - } else if (kind == it8712) { - type_name = "it8712"; - client_name = "IT8712 chip"; - } else { -#ifdef DEBUG - printk("it87.o: Internal error: unknown kind (%d)?!?", - kind); -#endif - goto ERROR1; - } - - /* Reserve the ISA region */ - if (is_isa) - request_region(address, IT87_EXTENT, type_name); - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* The IT8705F doesn't have VID capability */ - data->vid = 0x1f; - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - it87_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the IT87 chip */ - it87_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - if (is_isa) - release_region(address, IT87_EXTENT); - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int it87_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct it87_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("it87.o: Client deregistration failed, client not detached.\n"); - return err; - } - - if(i2c_is_isa_client(client)) - release_region(client->addr, IT87_EXTENT); - kfree(client->data); - - return 0; -} - -/* The SMBus locks itself, but ISA access must be locked explicitly! - We don't want to lock the whole ISA bus, so we lock each client - separately. - We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, - would slow down the IT87 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ -static int it87_read_value(struct i2c_client *client, u8 reg) -{ - int res; - if (i2c_is_isa_client(client)) { - down(&(((struct it87_data *) (client->data))->lock)); - outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET); - res = inb_p(client->addr + IT87_DATA_REG_OFFSET); - up(&(((struct it87_data *) (client->data))->lock)); - return res; - } else - return i2c_smbus_read_byte_data(client, reg); -} - -/* The SMBus locks itself, but ISA access muse be locked explicitly! - We don't want to lock the whole ISA bus, so we lock each client - separately. - We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, - would slow down the IT87 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ -static int it87_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - if (i2c_is_isa_client(client)) { - down(&(((struct it87_data *) (client->data))->lock)); - outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET); - outb_p(value, client->addr + IT87_DATA_REG_OFFSET); - up(&(((struct it87_data *) (client->data))->lock)); - return 0; - } else - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new IT87. */ -static void it87_init_client(struct i2c_client *client) -{ - int tmp; - - if (reset) { - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others */ - it87_write_value(client, IT87_REG_CONFIG, 0x80); - } - - /* Check if temperature channnels are reset manually or by some reason */ - tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE); - if ((tmp & 0x3f) == 0) { - /* Temp1,Temp3=thermistor; Temp2=thermal diode */ - tmp = (tmp & 0xc0) | 0x2a; - it87_write_value(client, IT87_REG_TEMP_ENABLE, tmp); - } - - /* Check if voltage monitors are reset manually or by some reason */ - tmp = it87_read_value(client, IT87_REG_VIN_ENABLE); - if ((tmp & 0xff) == 0) { - /* Enable all voltage monitors */ - it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff); - } - - /* Check if tachometers are reset manually or by some reason */ - tmp = it87_read_value(client, IT87_REG_FAN_CTRL); - if ((tmp & 0x70) == 0) { - /* Enable all fan tachometers */ - tmp = (tmp & 0x8f) | 0x70; - it87_write_value(client, IT87_REG_FAN_CTRL, tmp); - } - - /* Start monitoring */ - it87_write_value(client, IT87_REG_CONFIG, - (it87_read_value(client, IT87_REG_CONFIG) & 0x36) - | (update_vbat ? 0x41 : 0x01)); -} - -static void it87_update_client(struct i2c_client *client) -{ - struct it87_data *data = client->data; - int i, tmp, tmp2; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - - if (update_vbat) { - /* Cleared after each update, so reenable. Value - returned by this read will be previous value */ - it87_write_value(client, IT87_REG_CONFIG, - it87_read_value(client, IT87_REG_CONFIG) | 0x40); - } - for (i = 0; i <= 7; i++) { - data->in[i] = - it87_read_value(client, IT87_REG_VIN(i)); - data->in_min[i] = - it87_read_value(client, IT87_REG_VIN_MIN(i)); - data->in_max[i] = - it87_read_value(client, IT87_REG_VIN_MAX(i)); - } - data->in[8] = - it87_read_value(client, IT87_REG_VIN(8)); - /* VBAT sensor doesn't have limit registers, set - to min and max value */ - data->in_min[8] = 0; - data->in_max[8] = 255; - - for (i = 1; i <= 3; i++) { - data->fan[i - 1] = - it87_read_value(client, IT87_REG_FAN(i)); - data->fan_min[i - 1] = - it87_read_value(client, IT87_REG_FAN_MIN(i)); - } - for (i = 1; i <= 3; i++) { - data->temp[i - 1] = - it87_read_value(client, IT87_REG_TEMP(i)); - data->temp_high[i - 1] = - it87_read_value(client, IT87_REG_TEMP_HIGH(i)); - data->temp_low[i - 1] = - it87_read_value(client, IT87_REG_TEMP_LOW(i)); - } - - if (data->type == it8712) { - data->vid = it87_read_value(client, IT87_REG_VID); - data->vid &= 0x1f; - } - - i = it87_read_value(client, IT87_REG_FAN_DIV); - data->fan_div[0] = i & 0x07; - data->fan_div[1] = (i >> 3) & 0x07; - data->fan_div[2] = ( (i&0x40)==0x40 ? 3 : 1 ); - - for( i = 1; i <= 3; i++ ) { - data->pwm[i-1] = it87_read_value(client, IT87_REG_PWM(i)); - data->sg_tl[i-1][0] = it87_read_value(client, IT87_REG_SG_TL_OFF(i)); - data->sg_tl[i-1][1] = it87_read_value(client, IT87_REG_SG_TL_LOW(i)); - data->sg_tl[i-1][2] = it87_read_value(client, IT87_REG_SG_TL_MED(i)); - data->sg_tl[i-1][3] = it87_read_value(client, IT87_REG_SG_TL_HI(i)); - data->sg_tl[i-1][4] = it87_read_value(client, IT87_REG_SG_TL_OVR(i)); - data->sg_pwm[i-1][0] = it87_read_value(client, IT87_REG_SG_PWM_LOW(i)); - data->sg_pwm[i-1][1] = it87_read_value(client, IT87_REG_SG_PWM_MED(i)); - data->sg_pwm[i-1][2] = it87_read_value(client, IT87_REG_SG_PWM_HI(i)); - } - data->alarms = - it87_read_value(client, IT87_REG_ALARM1) | - (it87_read_value(client, IT87_REG_ALARM2) << 8) | - (it87_read_value(client, IT87_REG_ALARM3) << 16); - data->fan_ctl[0] = it87_read_value(client, IT87_REG_FAN_CTRL); - data->fan_ctl[1] = it87_read_value(client, IT87_REG_FAN_ONOFF); - - tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE); - for(i = 0; i < 3; i++) { - tmp2 = (tmp >> i) & 0x09; - if(tmp2 == 0x01) - data->sens[i] = PIIDIODE; - else if(tmp2 == 0x08) - data->sens[i] = THERMISTOR; - else - data->sens[i] = UNUSED; - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - - Each function must return the magnitude (power of 10 to divide the - data with) if it is called with operation==SENSORS_PROC_REAL_INFO. - - It must put a maximum of *nrels elements in results reflecting the - data of this file, and set *nrels to the number it actually put - in it, if operation==SENSORS_PROC_REAL_READ. - - Finally, it must get upto *nrels elements from results and write them - to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void it87_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - int nr = ctl_name - IT87_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0]); - it87_write_value(client, IT87_REG_VIN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1]); - it87_write_value(client, IT87_REG_VIN_MAX(nr), - data->in_max[nr]); - } - } -} - -void it87_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - int nr = ctl_name - IT87_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - results[1] = FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = FAN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr - 1])); - it87_write_value(client, IT87_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } - } -} - - -void it87_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - int nr = ctl_name - IT87_SYSCTL_TEMP1 + 1; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_high[nr - 1]); - results[1] = TEMP_FROM_REG(data->temp_low[nr - 1]); - results[2] = TEMP_FROM_REG(data->temp[nr - 1]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_high[nr - 1] = TEMP_TO_REG(results[0]); - it87_write_value(client, IT87_REG_TEMP_HIGH(nr), - data->temp_high[nr - 1]); - } - if (*nrels_mag >= 2) { - data->temp_low[nr - 1] = TEMP_TO_REG(results[1]); - it87_write_value(client, IT87_REG_TEMP_LOW(nr), - data->temp_low[nr - 1]); - } - } -} - -void it87_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - int nr = ctl_name - IT87_SYSCTL_PWM1 + 1; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = data->pwm[nr - 1]; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->pwm[nr - 1] = results[0]; - it87_write_value(client, IT87_REG_PWM(nr), data->pwm[nr - 1]); - } - } -} - -void it87_sgpwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - int nr = ctl_name - IT87_SYSCTL_PWM1 + 1; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = data->sg_pwm[nr - 1][0]; - results[1] = data->sg_pwm[nr - 1][1]; - results[2] = data->sg_pwm[nr - 1][2]; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->sg_pwm[nr - 1][0] = results[0]; - it87_write_value(client, IT87_REG_SG_PWM_LOW(nr), data->sg_pwm[nr - 1][0]); - } - if (*nrels_mag >= 2) { - data->sg_pwm[nr - 1][1] = results[1]; - it87_write_value(client, IT87_REG_SG_PWM_MED(nr), data->sg_pwm[nr - 1][1]); - } - if (*nrels_mag >= 3) { - data->sg_pwm[nr - 1][2] = results[2]; - it87_write_value(client, IT87_REG_SG_PWM_HI(nr), data->sg_pwm[nr - 1][2]); - } - } -} - -void it87_sgtl(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - int nr = ctl_name - IT87_SYSCTL_PWM1 + 1; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = TEMP_FROM_REG(data->sg_tl[nr - 1][0]); - results[1] = TEMP_FROM_REG(data->sg_tl[nr - 1][1]); - results[2] = TEMP_FROM_REG(data->sg_tl[nr - 1][2]); - results[3] = TEMP_FROM_REG(data->sg_tl[nr - 1][3]); - results[4] = TEMP_FROM_REG(data->sg_tl[nr - 1][4]); - *nrels_mag = 5; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->sg_tl[nr - 1][0] = TEMP_TO_REG(results[0]); - it87_write_value(client, IT87_REG_SG_TL_OFF(nr), data->sg_tl[nr - 1][0]); - } - if (*nrels_mag >= 2) { - data->sg_tl[nr - 1][1] = TEMP_TO_REG(results[1]); - it87_write_value(client, IT87_REG_SG_TL_LOW(nr), data->sg_tl[nr - 1][1]); - } - if (*nrels_mag >= 3) { - data->sg_tl[nr - 1][2] = TEMP_TO_REG(results[2]); - it87_write_value(client, IT87_REG_SG_TL_MED(nr), data->sg_tl[nr - 1][2]); - } - if (*nrels_mag >= 4) { - data->sg_tl[nr - 1][3] = TEMP_TO_REG(results[3]); - it87_write_value(client, IT87_REG_SG_TL_HI(nr), data->sg_tl[nr - 1][3]); - } - if (*nrels_mag >= 5) { - data->sg_tl[nr - 1][4] = TEMP_TO_REG(results[4]); - it87_write_value(client, IT87_REG_SG_TL_OVR(nr), data->sg_tl[nr - 1][4]); - } - } -} - -void it87_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = VID_FROM_REG(data->vid); - *nrels_mag = 1; - } -} - -void it87_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void it87_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - results[2] = DIV_FROM_REG(data->fan_div[2]);; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = it87_read_value(client, IT87_REG_FAN_DIV); - if (*nrels_mag >= 3) { - data->fan_div[2] = DIV_TO_REG(results[2]); - if (data->fan_div[2] != 3) { - data->fan_div[2] = 1; - old = (old & 0xbf); - } else { - old = (old | 0x40); - } - } - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0xc3) | (data->fan_div[1] << 3); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xf8) | data->fan_div[0]; - it87_write_value(client, IT87_REG_FAN_DIV, old); - } - } -} - -void it87_fan_ctl(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - int index = ctl_name - IT87_SYSCTL_FAN_CTL; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - it87_update_client(client); - results[0] = data->fan_ctl[index]; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_ctl[index] = results[0]; - if( index == 0 ) - it87_write_value(client, IT87_REG_FAN_CTRL, data->fan_ctl[index] ); - else - it87_write_value(client, IT87_REG_FAN_ONOFF, data->fan_ctl[index] ); - } - } -} - -void it87_sens(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct it87_data *data = client->data; - int nr = 1 + ctl_name - IT87_SYSCTL_SENS1; - u8 tmp, val1, val2; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->sens[nr - 1]; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - val1 = 0x01 << (nr - 1); - val2 = 0x08 << (nr - 1); - tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE); - switch (results[0]) { - case PIIDIODE: - tmp &= ~ val2; - tmp |= val1; - break; - case THERMISTOR: - tmp &= ~ val1; - tmp |= val2; - break; - case UNUSED: - tmp &= ~ val1; - tmp &= ~ val2; - break; - default: - printk(KERN_ERR "it87.o: Invalid sensor type %ld; " - "must be 0 (unused), 2 (thermistor) " - "or 3 (diode)\n", results[0]); - return; - } - it87_write_value(client, - IT87_REG_TEMP_ENABLE, tmp); - data->sens[nr - 1] = results[0]; - } - } -} - -static int __init sm_it87_init(void) -{ - int addr; - - printk("it87.o version %s (%s)\n", LM_VERSION, LM_DATE); - if (!it87_find(&addr)) { - normal_isa[0] = addr; - } - return i2c_add_driver(&it87_driver); -} - -static void __exit sm_it87_exit(void) -{ - i2c_del_driver(&it87_driver); -} - - -MODULE_AUTHOR("Chris Gauthron "); -MODULE_DESCRIPTION("IT8705F, IT8712F, Sis950 driver"); -MODULE_PARM(update_vbat, "i"); -MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); -MODULE_PARM(reset, "i"); -MODULE_PARM_DESC(reset, "Reset the chip's registers, default no"); - -module_init(sm_it87_init); -module_exit(sm_it87_exit); diff --git a/kernel/chips/lm63.c b/kernel/chips/lm63.c deleted file mode 100644 index 1f126477..00000000 --- a/kernel/chips/lm63.c +++ /dev/null @@ -1,645 +0,0 @@ -/* - * lm63.c - driver for the National Semiconductor LM63 temperature sensor - * with integrated fan control - * Copyright (C) 2004 Jean Delvare - * Based on the lm90 driver. - * - * The LM63 is a sensor chip made by National Semiconductor. It measures - * two temperatures (its own and one external one) and the speed of one - * fan, those speed it can additionally control. Complete datasheet can be - * obtained from National's website at: - * http://www.national.com/pf/LM/LM63.html - * - * The LM63 is basically an LM86 with fan speed monitoring and control - * capabilities added. It misses some of the LM86 features though: - * - No low limit for local temperature. - * - No critical limit for local temperature. - * - Critical limit for remote temperature can be changed only once. We - * will consider that the critical limit is read-only. - * - * The datasheet isn't very clear about what the tachometer reading is. - * I had a explanation from National Semiconductor though. The two lower - * bits of the read value have to be masked out. The value is still 16 bit - * in width. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include "version.h" - -/* - * Addresses to scan - * Address is fully defined internally and cannot be changed. - */ - -static unsigned short normal_i2c[] = { 0x4c, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(lm63); - -/* - * The LM63 registers - */ - -#define LM63_REG_CONFIG1 0x03 -#define LM63_REG_CONFIG2 0xBF -#define LM63_REG_CONFIG_FAN 0x4A - -#define LM63_REG_TACH_COUNT_MSB 0x47 -#define LM63_REG_TACH_COUNT_LSB 0x46 -#define LM63_REG_TACH_LIMIT_MSB 0x49 -#define LM63_REG_TACH_LIMIT_LSB 0x48 - -#define LM63_REG_PWM_VALUE 0x4C -#define LM63_REG_PWM_FREQ 0x4D - -#define LM63_REG_LOCAL_TEMP 0x00 -#define LM63_REG_LOCAL_HIGH 0x05 - -#define LM63_REG_REMOTE_TEMP_MSB 0x01 -#define LM63_REG_REMOTE_TEMP_LSB 0x10 -#define LM63_REG_REMOTE_OFFSET_MSB 0x11 -#define LM63_REG_REMOTE_OFFSET_LSB 0x12 -#define LM63_REG_REMOTE_HIGH_MSB 0x07 -#define LM63_REG_REMOTE_HIGH_LSB 0x13 -#define LM63_REG_REMOTE_LOW_MSB 0x08 -#define LM63_REG_REMOTE_LOW_LSB 0x14 -#define LM63_REG_REMOTE_TCRIT 0x19 -#define LM63_REG_REMOTE_TCRIT_HYST 0x21 - -#define LM63_REG_ALERT_STATUS 0x02 -#define LM63_REG_ALERT_MASK 0x16 - -#define LM63_REG_MAN_ID 0xFE -#define LM63_REG_CHIP_ID 0xFF - -/* - * Conversions and various macros - * For tachometer counts, the LM63 uses 16-bit values. - * For local temperature and high limit, remote critical limit and hysteresis - * value, it uses signed 8-bit values with LSB = 1 degree Celsius. - * For remote temperature, low and high limits, it uses signed 11-bit values - * with LSB = 0.125 degree Celsius, left-justified in 16-bit registers. - */ - -#define FAN_FROM_REG(reg) ((reg) == 0xFFFC || (reg) == 0 ? 0 : \ - 5400000 / (reg)) -#define FAN_TO_REG(val) ((val) <= 82 ? 0xFFFF : \ - (5400000 / (val)) & 0xFFFC) -#define TEMP8_FROM_REG(reg) (reg) -#define TEMP8_TO_REG(val) ((val) <= -128 ? -128 : \ - (val) >= 127 ? 127 : \ - val) -#define TEMP11_FROM_REG(reg) ((reg) / 32 * 125) -#define TEMP11_TO_REG(val) ((val) <= -128000 ? 0x8000 : \ - (val) >= 127875 ? 0x7FE0 : \ - (val) < 0 ? ((val) - 62) / 125 * 32 : \ - ((val) + 62) / 125 * 32) -#define HYST_TO_REG(val) ((val) <= 0 ? 0 : \ - (val) >= 127 ? 127 : \ - val) - -/* - * Functions declaration - */ - -static int lm63_attach_adapter(struct i2c_adapter *adapter); -static int lm63_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void lm63_init_client(struct i2c_client *client); -static int lm63_detach_client(struct i2c_client *client); - -static void lm63_local_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm63_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm63_remote_tcrit(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm63_remote_tcrit_hyst(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm63_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm63_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm63_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver lm63_driver = { - .name = "LM63 sensor driver", - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm63_attach_adapter, - .detach_client = lm63_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct lm63_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* registers values */ - u8 config, config_fan; - u16 fan1_input; - u16 fan1_low; - u8 pwm1_freq; - u8 pwm1_value; - s8 temp1_input; - s8 temp1_high; - s16 temp2_input; - s16 temp2_high; - s16 temp2_low; - s8 temp2_crit; - u8 temp2_crit_hyst; - u8 alarms; -}; - -/* - * Proc entries - * These files are created for each detected LM63. - */ - -/* -- SENSORS SYSCTL START -- */ - -#define LM63_SYSCTL_TEMP1 1200 -#define LM63_SYSCTL_TEMP2 1201 -#define LM63_SYSCTL_TEMP2_TCRIT 1205 -#define LM63_SYSCTL_TEMP2_TCRIT_HYST 1208 -#define LM63_SYSCTL_ALARMS 1210 -#define LM63_SYSCTL_FAN1 1220 -#define LM63_SYSCTL_PWM1 1230 - -#define LM63_ALARM_LOCAL_HIGH 0x40 -#define LM63_ALARM_REMOTE_HIGH 0x10 -#define LM63_ALARM_REMOTE_LOW 0x08 -#define LM63_ALARM_REMOTE_CRIT 0x02 -#define LM63_ALARM_REMOTE_OPEN 0x04 -#define LM63_ALARM_FAN_LOW 0x01 - -/* -- SENSORS SYSCTL END -- */ - -static ctl_table lm63_dir_table_template[] = -{ - {LM63_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm63_local_temp}, - {LM63_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm63_remote_temp}, - {LM63_SYSCTL_TEMP2_TCRIT, "temp2_crit", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm63_remote_tcrit}, - {LM63_SYSCTL_TEMP2_TCRIT_HYST, "temp2_crit_hyst", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm63_remote_tcrit_hyst}, - {LM63_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm63_alarms}, - {LM63_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm63_fan}, - {LM63_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm63_pwm}, - {0} -}; - -/* - * Real code - */ - -static int lm63_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, lm63_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int lm63_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - struct i2c_client *new_client; - struct lm63_data *data; - int err = 0; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { -#ifdef DEBUG - printk(KERN_DEBUG "lm63: adapter doesn't support SMBus byte " - "data mode, skipping.\n"); -#endif - return 0; - } - - if (!(data = kmalloc(sizeof(struct lm63_data), GFP_KERNEL))) { - printk(KERN_ERR "lm63: Out of memory in lm63_detect\n"); - return -ENOMEM; - } - - /* - * The common I2C client data is placed right before the - * LM63-specific data. The LM63-specific data is pointed to by the - * data field from the i2c_client structure. - */ - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &lm63_driver; - new_client->flags = 0; - - /* Default to an LM63 if forced */ - if (kind == 0) - kind = lm63; - - if (kind < 0) { /* must identify */ - u8 man_id, chip_id, reg_config1, reg_config2; - u8 reg_alert_status, reg_alert_mask; - - man_id = i2c_smbus_read_byte_data(new_client, - LM63_REG_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - LM63_REG_CHIP_ID); - reg_config1 = i2c_smbus_read_byte_data(new_client, - LM63_REG_CONFIG1); - reg_config2 = i2c_smbus_read_byte_data(new_client, - LM63_REG_CONFIG2); - reg_alert_status = i2c_smbus_read_byte_data(new_client, - LM63_REG_ALERT_STATUS); - reg_alert_mask = i2c_smbus_read_byte_data(new_client, - LM63_REG_ALERT_MASK); - - if (man_id == 0x01 /* National Semiconductor */ - && chip_id == 0x41 /* LM63 */ - && (reg_config1 & 0x18) == 0x00 - && (reg_config2 & 0xF8) == 0x00 - && (reg_alert_status & 0x20) == 0x00 - && (reg_alert_mask & 0xA4) == 0xA4) { - kind = lm63; - } else { -#ifdef DEBUG - printk(KERN_DEBUG "lm63: Unsupported chip " - "(man_id=0x%02X, chip_id=0x%02X)\n", - man_id, chip_id); -#endif - goto ERROR1; - } - } - - /* Fill in the remaining client fields */ - strcpy(new_client->name, "LM63 chip"); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) { - printk(KERN_ERR "lm63: Failed attaching client\n"); - goto ERROR1; - } - - /* Register a new directory entry */ - if ((err = i2c_register_entry(new_client, "lm63", - lm63_dir_table_template, THIS_MODULE)) < 0) { - printk(KERN_ERR "lm63: Failed registering directory entry\n"); - goto ERROR2; - } - data->sysctl_id = err; - - - /* Initialize the LM63 chip */ - lm63_init_client(new_client); - - return 0; - -ERROR2: - i2c_detach_client(new_client); -ERROR1: - kfree(data); - return err; -} - -/* Idealy we shouldn't have to initialize anything, since the BIOS - should have taken care of everything */ -static void lm63_init_client(struct i2c_client *client) -{ - struct lm63_data *data = client->data; - - data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1); - data->config_fan = i2c_smbus_read_byte_data(client, - LM63_REG_CONFIG_FAN); - - /* Start converting if needed */ - if (data->config & 0x40) { /* standby */ -#ifdef DEBUG - printk(KERN_DEBUG "lm63: Switching to operational mode"); -#endif - data->config &= 0xA7; - i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1, - data->config); - } - - /* We may need pwm1_freq before ever updating the client data */ - data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ); - if (data->pwm1_freq == 0) - data->pwm1_freq = 1; - -#ifdef DEBUG - /* Show some debug info about the LM63 configuration */ - printk(KERN_DEBUG "lm63: Alert/tach pin configured for %s\n", - (data->config & 0x04) ? "tachometer input" : - "alert output"); - printk(KERN_DEBUG "lm63: PWM clock %s kHz, output frequency %u Hz\n", - (data->config_fan & 0x08) ? "1.4" : "360", - ((data->config_fan & 0x08) ? 700 : 180000) / data->pwm1_freq); - printk(KERN_DEBUG "lm63: PWM output active %s, %s mode\n", - (data->config_fan & 0x10) ? "low" : "high", - (data->config_fan & 0x20) ? "manual" : "auto"); -#endif -} - -static int lm63_detach_client(struct i2c_client *client) -{ - struct lm63_data *data = client->data; - int err; - - i2c_deregister_entry(data->sysctl_id); - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR "lm63: Client deregistration failed, client " - "not detached.\n"); - return err; - } - - kfree(data); - return 0; -} - -static void lm63_update_client(struct i2c_client *client) -{ - struct lm63_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ) || - (jiffies < data->last_updated) || - !data->valid) { - if (data->config & 0x04) { /* tachometer enabled */ - /* order matters for fan1_input */ - data->fan1_input = i2c_smbus_read_byte_data(client, - LM63_REG_TACH_COUNT_LSB) & 0xFC; - data->fan1_input |= i2c_smbus_read_byte_data(client, - LM63_REG_TACH_COUNT_MSB) << 8; - data->fan1_low = (i2c_smbus_read_byte_data(client, - LM63_REG_TACH_LIMIT_LSB) & 0xFC) - | (i2c_smbus_read_byte_data(client, - LM63_REG_TACH_LIMIT_MSB) << 8); - } - - data->pwm1_freq = i2c_smbus_read_byte_data(client, - LM63_REG_PWM_FREQ); - if (data->pwm1_freq == 0) - data->pwm1_freq = 1; - data->pwm1_value = i2c_smbus_read_byte_data(client, - LM63_REG_PWM_VALUE); - - data->temp1_input = i2c_smbus_read_byte_data(client, - LM63_REG_LOCAL_TEMP); - data->temp1_high = i2c_smbus_read_byte_data(client, - LM63_REG_LOCAL_HIGH); - - /* order matters for temp2_input */ - data->temp2_input = i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TEMP_MSB) << 8; - data->temp2_input |= i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TEMP_LSB); - data->temp2_high = (i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_HIGH_MSB) << 8) - | i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_HIGH_LSB); - data->temp2_low = (i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_LOW_MSB) << 8) - | i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_LOW_LSB); - data->temp2_crit = i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TCRIT); - data->temp2_crit_hyst = i2c_smbus_read_byte_data(client, - LM63_REG_REMOTE_TCRIT_HYST); - - /* Mask out Busy bit in status register */ - data->alarms = i2c_smbus_read_byte_data(client, - LM63_REG_ALERT_STATUS) & 0x7F; - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -static void lm63_local_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm63_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm63_update_client(client); - results[0] = TEMP8_FROM_REG(data->temp1_high); - results[1] = TEMP8_FROM_REG(data->temp1_input); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp1_high = TEMP8_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, - data->temp1_high); - } - } -} - -static void lm63_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm63_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm63_update_client(client); - results[0] = TEMP11_FROM_REG(data->temp2_high); - results[1] = TEMP11_FROM_REG(data->temp2_low); - results[2] = TEMP11_FROM_REG(data->temp2_input); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp2_high = TEMP11_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, - LM63_REG_REMOTE_HIGH_MSB, - data->temp2_high >> 8); - i2c_smbus_write_byte_data(client, - LM63_REG_REMOTE_HIGH_LSB, - data->temp2_high & 0xFF); - } - if (*nrels_mag >= 2) { - data->temp2_low = TEMP11_TO_REG(results[1]); - i2c_smbus_write_byte_data(client, - LM63_REG_REMOTE_LOW_MSB, - data->temp2_low >> 8); - i2c_smbus_write_byte_data(client, - LM63_REG_REMOTE_LOW_LSB, - data->temp2_low & 0xFF); - } - } -} - -static void lm63_remote_tcrit(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm63_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm63_update_client(client); - results[0] = TEMP8_FROM_REG(data->temp2_crit); - *nrels_mag = 1; - } -} - -static void lm63_remote_tcrit_hyst(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm63_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm63_update_client(client); - results[0] = TEMP8_FROM_REG(data->temp2_crit) - - TEMP8_FROM_REG(data->temp2_crit_hyst); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp2_crit_hyst = HYST_TO_REG(data->temp2_crit - - results[0]); - i2c_smbus_write_byte_data(client, - LM63_REG_REMOTE_TCRIT_HYST, - data->temp2_crit_hyst); - } - } -} - -static void lm63_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm63_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm63_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -static void lm63_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm63_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - if (!(data->config & 0x04)) { /* tachometer disabled */ - results[0] = 0; - *nrels_mag = 1; - return; - } - - lm63_update_client(client); - results[0] = FAN_FROM_REG(data->fan1_low); - results[1] = FAN_FROM_REG(data->fan1_input); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (!(data->config & 0x04)) /* tachometer disabled */ - return; - - if (*nrels_mag >= 1) { - data->fan1_low = FAN_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, - LM63_REG_TACH_LIMIT_LSB, - data->fan1_low & 0xFF); - i2c_smbus_write_byte_data(client, - LM63_REG_TACH_LIMIT_MSB, - data->fan1_low >> 8); - } - } -} - -static void lm63_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm63_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm63_update_client(client); - results[0] = data->pwm1_value >= 2 * data->pwm1_freq ? 255 : - (data->pwm1_value * 255 + data->pwm1_freq) / - (2 * data->pwm1_freq); - results[1] = data->config_fan & 0x20 ? 1 : 2; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1 && (data->config_fan & 0x20)) { - data->pwm1_value = results[0] <= 0 ? 0 : - results[0] >= 255 ? 2 * data->pwm1_freq : - (results[0] * data->pwm1_freq * 2 + 127) / 255; - i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, - data->pwm1_value); - } - } -} - -static int __init lm63_init(void) -{ - printk(KERN_INFO "lm63 version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&lm63_driver); -} - -static void __exit lm63_exit(void) -{ - i2c_del_driver(&lm63_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("LM63 sensor driver"); -MODULE_LICENSE("GPL"); - -module_init(lm63_init); -module_exit(lm63_exit); diff --git a/kernel/chips/lm75.c b/kernel/chips/lm75.c deleted file mode 100644 index 1c8f539d..00000000 --- a/kernel/chips/lm75.c +++ /dev/null @@ -1,330 +0,0 @@ -/* - lm75.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include "version.h" -#include "lm75.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x48, 0x4f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(lm75); - -/* Many LM75 constants specified below */ - -/* The LM75 registers */ -#define LM75_REG_TEMP 0x00 -#define LM75_REG_CONF 0x01 -#define LM75_REG_TEMP_HYST 0x02 -#define LM75_REG_TEMP_OS 0x03 - -/* Each client has this additional data */ -struct lm75_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u16 temp, temp_os, temp_hyst; /* Register values */ -}; - -static int lm75_attach_adapter(struct i2c_adapter *adapter); -static int lm75_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void lm75_init_client(struct i2c_client *client); -static int lm75_detach_client(struct i2c_client *client); - -static int lm75_read_value(struct i2c_client *client, u8 reg); -static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value); -static void lm75_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm75_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver lm75_driver = { - .name = "LM75 sensor chip driver", - .id = I2C_DRIVERID_LM75, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm75_attach_adapter, - .detach_client = lm75_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define LM75_SYSCTL_TEMP 1200 /* Degrees Celsius * 10 */ - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected LM75. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table lm75_dir_table_template[] = { - {LM75_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm75_temp}, - {0} -}; - -static int lm75_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, lm75_detect); -} - -/* This function is called by i2c_detect */ -static int lm75_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct lm75_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("lm75.o: lm75_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA)) - goto error0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm75_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm75_data), GFP_KERNEL))) { - err = -ENOMEM; - goto error0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &lm75_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. There is no identification- - dedicated register so we have to rely on several tricks: - unused bits, registers cycling over 8-address boundaries, - addresses 0x04-0x07 returning the last read value. - The cycling+unused addresses combination is not tested, - since it would significantly slow the detection down and would - hardly add any value. */ - if (kind < 0) { - int cur, conf, hyst, os; - - /* Unused addresses */ - cur = i2c_smbus_read_word_data(new_client, 0); - conf = i2c_smbus_read_byte_data(new_client, 1); - hyst = i2c_smbus_read_word_data(new_client, 2); - if (i2c_smbus_read_word_data(new_client, 4) != hyst - || i2c_smbus_read_word_data(new_client, 5) != hyst - || i2c_smbus_read_word_data(new_client, 6) != hyst - || i2c_smbus_read_word_data(new_client, 7) != hyst) - goto error1; - os = i2c_smbus_read_word_data(new_client, 3); - if (i2c_smbus_read_word_data(new_client, 4) != os - || i2c_smbus_read_word_data(new_client, 5) != os - || i2c_smbus_read_word_data(new_client, 6) != os - || i2c_smbus_read_word_data(new_client, 7) != os) - goto error1; - - /* Unused bits */ - if (conf & 0xe0) - goto error1; - - /* Addresses cycling */ - for (i = 8; i < 0xff; i += 8) - if (i2c_smbus_read_byte_data(new_client, i + 1) != conf - || i2c_smbus_read_word_data(new_client, i + 2) != hyst - || i2c_smbus_read_word_data(new_client, i + 3) != os) - goto error1; - } - - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = lm75; - - if (kind == lm75) { - type_name = "lm75"; - client_name = "LM75 chip"; - } else { - pr_debug("lm75.o: Internal error: unknown kind (%d)?!?", kind); - goto error1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto error3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - lm75_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto error4; - } - data->sysctl_id = i; - - lm75_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - error4: - i2c_detach_client(new_client); - error3: - error1: - kfree(data); - error0: - return err; -} - -static int lm75_detach_client(struct i2c_client *client) -{ - struct lm75_data *data = client->data; - - i2c_deregister_entry(data->sysctl_id); - i2c_detach_client(client); - kfree(client->data); - return 0; -} - -/* All registers are word-sized, except for the configuration register. - LM75 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int lm75_read_value(struct i2c_client *client, u8 reg) -{ - if (reg == LM75_REG_CONF) - return i2c_smbus_read_byte_data(client, reg); - else - return swab16(i2c_smbus_read_word_data(client, reg)); -} - -/* All registers are word-sized, except for the configuration register. - LM75 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (reg == LM75_REG_CONF) - return i2c_smbus_write_byte_data(client, reg, value); - else - return i2c_smbus_write_word_data(client, reg, swab16(value)); -} - -static void lm75_init_client(struct i2c_client *client) -{ - int i; - - /* Enable if in shutdown mode */ - i = lm75_read_value(client, LM75_REG_CONF); - if (i >= 0 && (i & 0x01)) - lm75_write_value(client, LM75_REG_CONF, i & 0xfe); -} - -static void lm75_update_client(struct i2c_client *client) -{ - struct lm75_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - pr_debug("Starting lm75 update\n"); - - data->temp = lm75_read_value(client, LM75_REG_TEMP); - data->temp_os = lm75_read_value(client, LM75_REG_TEMP_OS); - data->temp_hyst = - lm75_read_value(client, LM75_REG_TEMP_HYST); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void lm75_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm75_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm75_update_client(client); - results[0] = LM75_TEMP_FROM_REG(data->temp_os); - results[1] = LM75_TEMP_FROM_REG(data->temp_hyst); - results[2] = LM75_TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_os = LM75_TEMP_TO_REG(results[0]); - lm75_write_value(client, LM75_REG_TEMP_OS, - data->temp_os); - } - if (*nrels_mag >= 2) { - data->temp_hyst = LM75_TEMP_TO_REG(results[1]); - lm75_write_value(client, LM75_REG_TEMP_HYST, - data->temp_hyst); - } - } -} - -static int __init sm_lm75_init(void) -{ - printk(KERN_INFO "lm75.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&lm75_driver); -} - -static void __exit sm_lm75_exit(void) -{ - i2c_del_driver(&lm75_driver); -} - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("LM75 driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_lm75_init); -module_exit(sm_lm75_exit); diff --git a/kernel/chips/lm75.h b/kernel/chips/lm75.h deleted file mode 100644 index 2180f976..00000000 --- a/kernel/chips/lm75.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - lm75.h - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2003 Mark M. Hoffman - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - This file contains common code for encoding/decoding LM75 type - temperature readings, which are emulated by many of the chips - we support. As the user is unlikely to load more than one driver - which contains this code, we don't worry about the wasted space. -*/ - -#include - -/* straight from the datasheet */ -#define LM75_TEMP_MIN (-550) -#define LM75_TEMP_MAX 1250 - -/* TEMP: 0.1C/bit (-55C to +125C) - REG: (0.5C/bit, two's complement) << 7 */ -static inline u16 LM75_TEMP_TO_REG(int temp) -{ - int ntemp = SENSORS_LIMIT(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); - ntemp += (ntemp<0 ? -2 : 2); - return (u16)((ntemp / 5) << 7); -} - -static inline int LM75_TEMP_FROM_REG(u16 reg) -{ - /* use integer division instead of equivalent right shift to - guarantee arithmetic shift and preserve the sign */ - return ((s16)reg / 128) * 5; -} - diff --git a/kernel/chips/lm78.c b/kernel/chips/lm78.c deleted file mode 100644 index 6598170a..00000000 --- a/kernel/chips/lm78.c +++ /dev/null @@ -1,721 +0,0 @@ -/* - lm78.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x20, 0x2f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0x0290, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_3(lm78, lm78j, lm79); - -/* Many LM78 constants specified below */ - -/* Length of ISA address segment */ -#define LM78_EXTENT 8 - -/* Where are the ISA address/data registers relative to the base address */ -#define LM78_ADDR_REG_OFFSET 5 -#define LM78_DATA_REG_OFFSET 6 - -/* The LM78 registers */ -#define LM78_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define LM78_REG_IN_MIN(nr) (0x2c + (nr) * 2) -#define LM78_REG_IN(nr) (0x20 + (nr)) - -#define LM78_REG_FAN_MIN(nr) (0x3a + (nr)) -#define LM78_REG_FAN(nr) (0x27 + (nr)) - -#define LM78_REG_TEMP 0x27 -#define LM78_REG_TEMP_OVER 0x39 -#define LM78_REG_TEMP_HYST 0x3a - -#define LM78_REG_ALARM1 0x41 -#define LM78_REG_ALARM2 0x42 - -#define LM78_REG_VID_FANDIV 0x47 - -#define LM78_REG_CONFIG 0x40 -#define LM78_REG_CHIPID 0x49 -#define LM78_REG_I2C_ADDR 0x48 - - -/* Conversions. Limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) -#define IN_FROM_REG(val) (((val) * 16 + 5) / 10) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm <= 0) - return 255; - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) - -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-5)/10):\ - ((val)+5)/10), -128, 127)) -#define TEMP_FROM_REG(val) ((val)*10) - -#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ - 205-(val)*5) - -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) -#define DIV_FROM_REG(val) (1 << (val)) - -/* There are some complications in a module like this. First off, LM78 chips - may be both present on the SMBus and the ISA bus, and we have to handle - those cases separately at some places. Second, there might be several - LM78 chips available (well, actually, that is probably never done; but - it is a clean illustration of how to handle a case like that). Finally, - a specific chip may be attached to *both* ISA and SMBus, and we would - not like to detect it double. Fortunately, in the case of the LM78 at - least, a register tells us what SMBus address we are on, so that helps - a bit - except if there could be more than one SMBus. Groan. No solution - for this yet. */ - -/* This module may seem overly long and complicated. In fact, it is not so - bad. Quite a lot of bookkeeping is done. A real driver can often cut - some corners. */ - -/* For each registered LM78, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new lm78 client is - allocated. */ -struct lm78_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - s8 temp; /* Register value */ - s8 temp_over; /* Register value */ - s8 temp_hyst; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ - u16 alarms; /* Register encoding, combined */ -}; - - -static int lm78_attach_adapter(struct i2c_adapter *adapter); -static int lm78_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int lm78_detach_client(struct i2c_client *client); - -static int lm78_read_value(struct i2c_client *client, u8 register); -static int lm78_write_value(struct i2c_client *client, u8 register, - u8 value); -static void lm78_update_client(struct i2c_client *client); -static void lm78_init_client(struct i2c_client *client); - - -static void lm78_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void lm78_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm78_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm78_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm78_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm78_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver lm78_driver = { - .name = "LM78(-J) and LM79 sensor driver", - .id = I2C_DRIVERID_LM78, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm78_attach_adapter, - .detach_client = lm78_detach_client, -}; - -/* The /proc/sys entries */ - -/* -- SENSORS SYSCTL START -- */ -#define LM78_SYSCTL_IN0 1000 /* Volts * 100 */ -#define LM78_SYSCTL_IN1 1001 -#define LM78_SYSCTL_IN2 1002 -#define LM78_SYSCTL_IN3 1003 -#define LM78_SYSCTL_IN4 1004 -#define LM78_SYSCTL_IN5 1005 -#define LM78_SYSCTL_IN6 1006 -#define LM78_SYSCTL_FAN1 1101 /* Rotations/min */ -#define LM78_SYSCTL_FAN2 1102 -#define LM78_SYSCTL_FAN3 1103 -#define LM78_SYSCTL_TEMP 1200 /* Degrees Celsius * 10 */ -#define LM78_SYSCTL_VID 1300 /* Volts * 100 */ -#define LM78_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define LM78_SYSCTL_ALARMS 2001 /* bitvector */ - -#define LM78_ALARM_IN0 0x0001 -#define LM78_ALARM_IN1 0x0002 -#define LM78_ALARM_IN2 0x0004 -#define LM78_ALARM_IN3 0x0008 -#define LM78_ALARM_IN4 0x0100 -#define LM78_ALARM_IN5 0x0200 -#define LM78_ALARM_IN6 0x0400 -#define LM78_ALARM_FAN1 0x0040 -#define LM78_ALARM_FAN2 0x0080 -#define LM78_ALARM_FAN3 0x0800 -#define LM78_ALARM_TEMP 0x0010 -#define LM78_ALARM_BTI 0x0020 -#define LM78_ALARM_CHAS 0x1000 -#define LM78_ALARM_FIFO 0x2000 -#define LM78_ALARM_SMI_IN 0x4000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected LM78. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table lm78_dir_table_template[] = { - {LM78_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_in}, - {LM78_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_in}, - {LM78_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_in}, - {LM78_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_in}, - {LM78_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_in}, - {LM78_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_in}, - {LM78_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_in}, - {LM78_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_fan}, - {LM78_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_fan}, - {LM78_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_fan}, - {LM78_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_temp}, - {LM78_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_vid}, - {LM78_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_fan_div}, - {LM78_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm78_alarms}, - {0} -}; - - -/* This function is called when: - * lm78_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and lm78_driver is still present) */ -static int lm78_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, lm78_detect); -} - -/* This function is called by i2c_detect */ -static int lm78_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct lm78_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - int is_isa = i2c_is_isa_adapter(adapter); - - if (!is_isa - && !i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BYTE_DATA)) goto - ERROR0; - - if (is_isa) { - if (check_region(address, LM78_EXTENT)) - goto ERROR0; - } - - /* Probe whether there is anything available on this address. Already - done for SMBus clients */ - if (kind < 0) { - if (is_isa) { - -#define REALLY_SLOW_IO - /* We need the timeouts for at least some LM78-like chips. But only - if we read 'undefined' registers. */ - i = inb_p(address + 1); - if (inb_p(address + 2) != i) - goto ERROR0; - if (inb_p(address + 3) != i) - goto ERROR0; - if (inb_p(address + 7) != i) - goto ERROR0; -#undef REALLY_SLOW_IO - - /* Let's just hope nothing breaks here */ - i = inb_p(address + 5) & 0x7f; - outb_p(~i & 0x7f, address + 5); - if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { - outb_p(i, address + 5); - return 0; - } - } - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm78_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct lm78_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - if (is_isa) - init_MUTEX(&data->lock); - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &lm78_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if (lm78_read_value(new_client, LM78_REG_CONFIG) & 0x80) - goto ERROR1; - if (!is_isa - && (lm78_read_value(new_client, LM78_REG_I2C_ADDR) != - address)) goto ERROR1; - } - - /* Determine the chip type. */ - if (kind <= 0) { - i = lm78_read_value(new_client, LM78_REG_CHIPID); - if (i == 0x00 || i == 0x20) - kind = lm78; - else if (i == 0x40) - kind = lm78j; - else if ((i & 0xfe) == 0xc0) - kind = lm79; - else { - if (kind == 0) - printk - ("lm78.o: Ignoring 'force' parameter for unknown chip at " - "adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - goto ERROR1; - } - } - - if (kind == lm78) { - type_name = "lm78"; - client_name = "LM78 chip"; - } else if (kind == lm78j) { - type_name = "lm78-j"; - client_name = "LM78-J chip"; - } else if (kind == lm79) { - type_name = "lm79"; - client_name = "LM79 chip"; - } else { -#ifdef DEBUG - printk("lm78.o: Internal error: unknown kind (%d)?!?", - kind); -#endif - goto ERROR1; - } - - /* Reserve the ISA region */ - if (is_isa) - request_region(address, LM78_EXTENT, type_name); - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - lm78_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the LM78 chip */ - lm78_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - if (is_isa) - release_region(address, LM78_EXTENT); - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int lm78_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct lm78_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("lm78.o: Client deregistration failed, client not detached.\n"); - return err; - } - - if(i2c_is_isa_client(client)) - release_region(client->addr, LM78_EXTENT); - kfree(client->data); - - return 0; -} - -/* The SMBus locks itself, but ISA access must be locked explicitly! - We don't want to lock the whole ISA bus, so we lock each client - separately. - We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM78 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ -static int lm78_read_value(struct i2c_client *client, u8 reg) -{ - int res; - if (i2c_is_isa_client(client)) { - down(&(((struct lm78_data *) (client->data))->lock)); - outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); - res = inb_p(client->addr + LM78_DATA_REG_OFFSET); - up(&(((struct lm78_data *) (client->data))->lock)); - return res; - } else - return i2c_smbus_read_byte_data(client, reg); -} - -/* The SMBus locks itself, but ISA access muse be locked explicitly! - We don't want to lock the whole ISA bus, so we lock each client - separately. - We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM78 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ -static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - if (i2c_is_isa_client(client)) { - down(&(((struct lm78_data *) (client->data))->lock)); - outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); - outb_p(value, client->addr + LM78_DATA_REG_OFFSET); - up(&(((struct lm78_data *) (client->data))->lock)); - return 0; - } else - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new LM78. */ -static void lm78_init_client(struct i2c_client *client) -{ - u8 config = lm78_read_value(client, LM78_REG_CONFIG); - - /* Start monitoring */ - if (!(config & 0x01)) - lm78_write_value(client, LM78_REG_CONFIG, - (config & 0xf7) | 0x01); -} - -static void lm78_update_client(struct i2c_client *client) -{ - struct lm78_data *data = client->data; - int i; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting lm78 update\n"); -#endif - for (i = 0; i <= 6; i++) { - data->in[i] = - lm78_read_value(client, LM78_REG_IN(i)); - data->in_min[i] = - lm78_read_value(client, LM78_REG_IN_MIN(i)); - data->in_max[i] = - lm78_read_value(client, LM78_REG_IN_MAX(i)); - } - for (i = 1; i <= 3; i++) { - data->fan[i - 1] = - lm78_read_value(client, LM78_REG_FAN(i)); - data->fan_min[i - 1] = - lm78_read_value(client, LM78_REG_FAN_MIN(i)); - } - data->temp = lm78_read_value(client, LM78_REG_TEMP); - data->temp_over = - lm78_read_value(client, LM78_REG_TEMP_OVER); - data->temp_hyst = - lm78_read_value(client, LM78_REG_TEMP_HYST); - i = lm78_read_value(client, LM78_REG_VID_FANDIV); - data->vid = i & 0x0f; - if (data->type == lm79) - data->vid |= - (lm78_read_value(client, LM78_REG_CHIPID) & - 0x01) << 4; - else - data->vid |= 0x10; - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = lm78_read_value(client, LM78_REG_ALARM1) + - (lm78_read_value(client, LM78_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = 1; - - data->fan_div[2] = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void lm78_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm78_data *data = client->data; - int nr = ctl_name - LM78_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm78_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0]); - lm78_write_value(client, LM78_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1]); - lm78_write_value(client, LM78_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void lm78_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm78_data *data = client->data; - int nr = ctl_name - LM78_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm78_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data-> - fan_div[nr - 1])); - results[1] = - FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = FAN_TO_REG(results[0], - DIV_FROM_REG - (data-> - fan_div[nr - - 1])); - lm78_write_value(client, LM78_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } - } -} - - -void lm78_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm78_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm78_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over = TEMP_TO_REG(results[0]); - lm78_write_value(client, LM78_REG_TEMP_OVER, - data->temp_over); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - lm78_write_value(client, LM78_REG_TEMP_HYST, - data->temp_hyst); - } - } -} - -void lm78_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm78_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm78_update_client(client); - results[0] = VID_FROM_REG(data->vid); - *nrels_mag = 1; - } -} - -void lm78_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm78_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm78_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -/* Note: we save and restore the fan minimum here, because its value is - determined in part by the fan divisor. This follows the principle of - least surprise: the user doesn't expect the fan minimum to change just - because the divisor changed. */ -void lm78_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm78_data *data = client->data; - int old, min; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm78_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - results[2] = 2; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = lm78_read_value(client, LM78_REG_VID_FANDIV); - if (*nrels_mag >= 2) { - min = FAN_FROM_REG(data->fan_min[1], - DIV_FROM_REG(data->fan_div[1])); - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan_div[1] << 6); - data->fan_min[1] = FAN_TO_REG(min, - DIV_FROM_REG(data->fan_div[1])); - lm78_write_value(client, LM78_REG_FAN_MIN(2), - data->fan_min[1]); - } - if (*nrels_mag >= 1) { - min = FAN_FROM_REG(data->fan_min[0], - DIV_FROM_REG(data->fan_div[0])); - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div[0] << 4); - data->fan_min[0] = FAN_TO_REG(min, - DIV_FROM_REG(data->fan_div[0])); - lm78_write_value(client, LM78_REG_FAN_MIN(1), - data->fan_min[0]); - lm78_write_value(client, LM78_REG_VID_FANDIV, old); - } - } -} - -static int __init sm_lm78_init(void) -{ - printk("lm78.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&lm78_driver); -} - -static void __exit sm_lm78_exit(void) -{ - i2c_del_driver(&lm78_driver); -} - - - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver"); - -module_init(sm_lm78_init); -module_exit(sm_lm78_exit); diff --git a/kernel/chips/lm80.c b/kernel/chips/lm80.c deleted file mode 100644 index 7584306b..00000000 --- a/kernel/chips/lm80.c +++ /dev/null @@ -1,599 +0,0 @@ -/* - lm80.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - and Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x20, 0x2f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(lm80); - -/* Many LM80 constants specified below */ - -/* The LM80 registers */ -#define LM80_REG_IN_MAX(nr) (0x2a + (nr) * 2) -#define LM80_REG_IN_MIN(nr) (0x2b + (nr) * 2) -#define LM80_REG_IN(nr) (0x20 + (nr)) - -#define LM80_REG_FAN1_MIN 0x3c -#define LM80_REG_FAN2_MIN 0x3d -#define LM80_REG_FAN1 0x28 -#define LM80_REG_FAN2 0x29 - -#define LM80_REG_TEMP 0x27 -#define LM80_REG_TEMP_HOT_MAX 0x38 -#define LM80_REG_TEMP_HOT_HYST 0x39 -#define LM80_REG_TEMP_OS_MAX 0x3a -#define LM80_REG_TEMP_OS_HYST 0x3b - -#define LM80_REG_CONFIG 0x00 -#define LM80_REG_ALARM1 0x01 -#define LM80_REG_ALARM2 0x02 -#define LM80_REG_MASK1 0x03 -#define LM80_REG_MASK2 0x04 -#define LM80_REG_FANDIV 0x05 -#define LM80_REG_RES 0x06 - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - -#define IN_TO_REG(val) (SENSORS_LIMIT((val),0,255)) -#define IN_FROM_REG(val) (val) - -static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:\ - (val)==255?0:1350000/((div)*(val))) - -static inline long TEMP_FROM_REG(u16 temp) -{ - long res; - - temp >>= 4; - if (temp < 0x0800) - res = 625 * (long) temp; - else - res = ((long) temp - 0x01000) * 625; - - return res / 100; -} - -#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*100) - -#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT(((val)<0?(((val)-50)/100):\ - ((val)+50)/100), \ - 0,255) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) - -struct lm80_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u16 temp; /* Register values, shifted right */ - u8 temp_hot_max; /* Register value */ - u8 temp_hot_hyst; /* Register value */ - u8 temp_os_max; /* Register value */ - u8 temp_os_hyst; /* Register value */ - u16 alarms; /* Register encoding, combined */ -}; - - - -static int lm80_attach_adapter(struct i2c_adapter *adapter); -static int lm80_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int lm80_detach_client(struct i2c_client *client); - -static int lm80_read_value(struct i2c_client *client, u8 reg); -static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value); -static void lm80_update_client(struct i2c_client *client); -static void lm80_init_client(struct i2c_client *client); - - -static void lm80_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void lm80_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm80_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm80_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm80_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver lm80_driver = { - .name = "LM80 sensor driver", - .id = I2C_DRIVERID_LM80, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm80_attach_adapter, - .detach_client = lm80_detach_client, -}; - -/* The /proc/sys entries */ - -/* -- SENSORS SYSCTL START -- */ - -#define LM80_SYSCTL_IN0 1000 /* Volts * 100 */ -#define LM80_SYSCTL_IN1 1001 -#define LM80_SYSCTL_IN2 1002 -#define LM80_SYSCTL_IN3 1003 -#define LM80_SYSCTL_IN4 1004 -#define LM80_SYSCTL_IN5 1005 -#define LM80_SYSCTL_IN6 1006 -#define LM80_SYSCTL_FAN1 1101 /* Rotations/min */ -#define LM80_SYSCTL_FAN2 1102 -#define LM80_SYSCTL_TEMP 1250 /* Degrees Celsius * 100 */ -#define LM80_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define LM80_SYSCTL_ALARMS 2001 /* bitvector */ - -#define LM80_ALARM_IN0 0x0001 -#define LM80_ALARM_IN1 0x0002 -#define LM80_ALARM_IN2 0x0004 -#define LM80_ALARM_IN3 0x0008 -#define LM80_ALARM_IN4 0x0010 -#define LM80_ALARM_IN5 0x0020 -#define LM80_ALARM_IN6 0x0040 -#define LM80_ALARM_FAN1 0x0400 -#define LM80_ALARM_FAN2 0x0800 -#define LM80_ALARM_TEMP_HOT 0x0100 -#define LM80_ALARM_TEMP_OS 0x2000 -#define LM80_ALARM_CHAS 0x1000 -#define LM80_ALARM_BTI 0x0200 -#define LM80_ALARM_INT_IN 0x0080 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected LM80. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table lm80_dir_table_template[] = { - {LM80_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_in}, - {LM80_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_in}, - {LM80_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_in}, - {LM80_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_in}, - {LM80_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_in}, - {LM80_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_in}, - {LM80_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_in}, - {LM80_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_fan}, - {LM80_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_fan}, - {LM80_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_temp}, - {LM80_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_fan_div}, - {LM80_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm80_alarms}, - {0} -}; - -static int lm80_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, lm80_detect); -} - -static int lm80_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i, cur; - struct i2c_client *new_client; - struct lm80_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("lm80.o: lm80_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm80_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct lm80_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &lm80_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. It is lousy. */ - if (lm80_read_value(new_client, LM80_REG_ALARM2) & 0xc0) - goto ERROR1; - for (i = 0x2a; i <= 0x3d; i++) { - cur = i2c_smbus_read_byte_data(new_client, i); - if ((i2c_smbus_read_byte_data(new_client, i + 0x40) != cur) - || (i2c_smbus_read_byte_data(new_client, i + 0x80) != - cur) - || (i2c_smbus_read_byte_data(new_client, i + 0xc0) != - cur)) goto ERROR1; - } - - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = lm80; - - if (kind == lm80) { - type_name = "lm80"; - client_name = "LM80 chip"; - } else { -#ifdef DEBUG - printk("lm80.o: Internal error: unknown kind (%d)?!?", - kind); -#endif - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - lm80_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - lm80_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int lm80_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct lm80_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("lm80.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -static int lm80_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new LM80. */ -static void lm80_init_client(struct i2c_client *client) -{ - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others. This makes most other - initializations unnecessary */ - lm80_write_value(client, LM80_REG_CONFIG, 0x80); - /* Set 11-bit temperature resolution */ - lm80_write_value(client, LM80_REG_RES, 0x08); - - /* Start monitoring */ - lm80_write_value(client, LM80_REG_CONFIG, 0x01); -} - -static void lm80_update_client(struct i2c_client *client) -{ - struct lm80_data *data = client->data; - int i; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 2 * HZ) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting lm80 update\n"); -#endif - for (i = 0; i <= 6; i++) { - data->in[i] = - lm80_read_value(client, LM80_REG_IN(i)); - data->in_min[i] = - lm80_read_value(client, LM80_REG_IN_MIN(i)); - data->in_max[i] = - lm80_read_value(client, LM80_REG_IN_MAX(i)); - } - data->fan[0] = lm80_read_value(client, LM80_REG_FAN1); - data->fan_min[0] = - lm80_read_value(client, LM80_REG_FAN1_MIN); - data->fan[1] = lm80_read_value(client, LM80_REG_FAN2); - data->fan_min[1] = - lm80_read_value(client, LM80_REG_FAN2_MIN); - - data->temp = - (lm80_read_value(client, LM80_REG_TEMP) << 8) | - (lm80_read_value(client, LM80_REG_RES) & 0xf0); - data->temp_os_max = - lm80_read_value(client, LM80_REG_TEMP_OS_MAX); - data->temp_os_hyst = - lm80_read_value(client, LM80_REG_TEMP_OS_HYST); - data->temp_hot_max = - lm80_read_value(client, LM80_REG_TEMP_HOT_MAX); - data->temp_hot_hyst = - lm80_read_value(client, LM80_REG_TEMP_HOT_HYST); - - i = lm80_read_value(client, LM80_REG_FANDIV); - data->fan_div[0] = (i >> 2) & 0x03; - data->fan_div[1] = (i >> 4) & 0x03; - data->alarms = lm80_read_value(client, LM80_REG_ALARM1) + - (lm80_read_value(client, LM80_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void lm80_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm80_data *data = client->data; - int nr = ctl_name - LM80_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm80_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0]); - lm80_write_value(client, LM80_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1]); - lm80_write_value(client, LM80_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void lm80_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm80_data *data = client->data; - int nr = ctl_name - LM80_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm80_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data-> - fan_div[nr - 1])); - results[1] = - FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = FAN_TO_REG(results[0], - DIV_FROM_REG - (data-> - fan_div[nr - - 1])); - lm80_write_value(client, - nr == - 1 ? LM80_REG_FAN1_MIN : - LM80_REG_FAN2_MIN, - data->fan_min[nr - 1]); - } - } -} - - -void lm80_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm80_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm80_update_client(client); - results[0] = TEMP_LIMIT_FROM_REG(data->temp_hot_max); - results[1] = TEMP_LIMIT_FROM_REG(data->temp_hot_hyst); - results[2] = TEMP_LIMIT_FROM_REG(data->temp_os_max); - results[3] = TEMP_LIMIT_FROM_REG(data->temp_os_hyst); - results[4] = TEMP_FROM_REG(data->temp); - *nrels_mag = 5; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_hot_max = TEMP_LIMIT_TO_REG(results[0]); - lm80_write_value(client, LM80_REG_TEMP_HOT_MAX, - data->temp_hot_max); - } - if (*nrels_mag >= 2) { - data->temp_hot_hyst = - TEMP_LIMIT_TO_REG(results[1]); - lm80_write_value(client, LM80_REG_TEMP_HOT_HYST, - data->temp_hot_hyst); - } - if (*nrels_mag >= 3) { - data->temp_os_max = TEMP_LIMIT_TO_REG(results[2]); - lm80_write_value(client, LM80_REG_TEMP_OS_MAX, - data->temp_os_max); - } - if (*nrels_mag >= 4) { - data->temp_os_hyst = TEMP_LIMIT_TO_REG(results[3]); - lm80_write_value(client, LM80_REG_TEMP_OS_HYST, - data->temp_os_hyst); - } - } -} - -void lm80_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm80_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm80_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -void lm80_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm80_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm80_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - results[2] = 2; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = lm80_read_value(client, LM80_REG_FANDIV); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0xcf) | (data->fan_div[1] << 4); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xf3) | (data->fan_div[0] << 2); - lm80_write_value(client, LM80_REG_FANDIV, old); - } - } -} - -static int __init sm_lm80_init(void) -{ - printk("lm80.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&lm80_driver); -} - -static void __exit sm_lm80_exit(void) -{ - i2c_del_driver(&lm80_driver); -} - - - -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("LM80 driver"); - -module_init(sm_lm80_init); -module_exit(sm_lm80_exit); diff --git a/kernel/chips/lm83.c b/kernel/chips/lm83.c deleted file mode 100644 index d58d5c9d..00000000 --- a/kernel/chips/lm83.c +++ /dev/null @@ -1,528 +0,0 @@ -/* - * lm83.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2003 Jean Delvare - * - * Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is - * a sensor chip made by National Semiconductor. It reports up to four - * temperatures (its own plus up to three external ones) with a 1 deg - * resolution and a 3-4 deg accuracy. Complete datasheet can be obtained - * from National's website at: - * http://www.national.com/pf/LM/LM83.html - * Since the datasheet omits to give the chip stepping code, I give it - * here: 0x03 (at register 0xff). - * - * Also supports the LM82 temp sensor, which is basically a stripped down - * model of the LM83. Datasheet is here: - * http://www.national.com/pf/LM/LM82.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include "version.h" - -/* - * Addresses to scan - * Address is selected using 2 three-level pins, resulting in 9 possible - * addresses. - */ - -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x18, 0x1a, 0x29, 0x2b, - 0x4c, 0x4e, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_2(lm83, lm82); - -/* - * The LM83 registers - * Manufacturer ID is 0x01 for National Semiconductor. - */ - -#define LM83_REG_R_MAN_ID 0xFE -#define LM83_REG_R_CHIP_ID 0xFF -#define LM83_REG_R_CONFIG 0x03 -#define LM83_REG_W_CONFIG 0x09 -#define LM83_REG_R_STATUS1 0x02 -#define LM83_REG_R_STATUS2 0x35 -#define LM83_REG_R_LOCAL_TEMP 0x00 -#define LM83_REG_R_LOCAL_HIGH 0x05 -#define LM83_REG_W_LOCAL_HIGH 0x0B -#define LM83_REG_R_REMOTE1_TEMP 0x30 -#define LM83_REG_R_REMOTE1_HIGH 0x38 -#define LM83_REG_W_REMOTE1_HIGH 0x50 -#define LM83_REG_R_REMOTE2_TEMP 0x01 -#define LM83_REG_R_REMOTE2_HIGH 0x07 -#define LM83_REG_W_REMOTE2_HIGH 0x0D -#define LM83_REG_R_REMOTE3_TEMP 0x31 -#define LM83_REG_R_REMOTE3_HIGH 0x3A -#define LM83_REG_W_REMOTE3_HIGH 0x52 -#define LM83_REG_R_TCRIT 0x42 -#define LM83_REG_W_TCRIT 0x5A - -/* - * Conversions and various macros - * The LM83 uses signed 8-bit values with LSB = 1 degree Celsius. - */ - -#define TEMP_FROM_REG(val) (val) -#define TEMP_TO_REG(val) ((val) <= -50 ? -50 : \ - (val) >= 127 ? 127 : (val)) - -static const u8 LM83_REG_R_TEMP[] = { - LM83_REG_R_LOCAL_TEMP, - LM83_REG_R_REMOTE1_TEMP, - LM83_REG_R_REMOTE2_TEMP, - LM83_REG_R_REMOTE3_TEMP -}; - -static const u8 LM83_REG_R_HIGH[] = { - LM83_REG_R_LOCAL_HIGH, - LM83_REG_R_REMOTE1_HIGH, - LM83_REG_R_REMOTE2_HIGH, - LM83_REG_R_REMOTE3_HIGH -}; - -static const u8 LM83_REG_W_HIGH[] = { - LM83_REG_W_LOCAL_HIGH, - LM83_REG_W_REMOTE1_HIGH, - LM83_REG_W_REMOTE2_HIGH, - LM83_REG_W_REMOTE3_HIGH -}; - -/* - * Functions declaration - */ - -static int lm83_attach_adapter(struct i2c_adapter *adapter); -static int lm83_detect(struct i2c_adapter *adapter, int address, unsigned - short flags, int kind); -static int lm83_detach_client(struct i2c_client *client); -static void lm83_update_client(struct i2c_client *client); -static void lm83_temp(struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results); -static void lm83_tcrit(struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results); -static void lm83_alarms(struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver lm83_driver = { - .name = "LM83 sensor driver", - .id = I2C_DRIVERID_LM83, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm83_attach_adapter, - .detach_client = lm83_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct lm83_data -{ - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* registers values */ - s8 temp[4], temp_high[4], tcrit; - u16 alarms; /* bitvector, combined */ -}; - -/* - * Proc entries - * These files are created for each detected LM83. - */ - -/* -- SENSORS SYSCTL START -- */ - -#define LM83_SYSCTL_LOCAL_TEMP 1200 -#define LM83_SYSCTL_REMOTE1_TEMP 1201 -#define LM83_SYSCTL_REMOTE2_TEMP 1202 -#define LM83_SYSCTL_REMOTE3_TEMP 1203 -#define LM83_SYSCTL_TCRIT 1208 -#define LM83_SYSCTL_ALARMS 1210 - -#define LM83_ALARM_LOCAL_HIGH 0x0040 -#define LM83_ALARM_LOCAL_CRIT 0x0001 -#define LM83_ALARM_REMOTE1_HIGH 0x8000 -#define LM83_ALARM_REMOTE1_CRIT 0x0100 -#define LM83_ALARM_REMOTE1_OPEN 0x2000 -#define LM83_ALARM_REMOTE2_HIGH 0x0010 -#define LM83_ALARM_REMOTE2_CRIT 0x0002 -#define LM83_ALARM_REMOTE2_OPEN 0x0004 -#define LM83_ALARM_REMOTE3_HIGH 0x1000 -#define LM83_ALARM_REMOTE3_CRIT 0x0200 -#define LM83_ALARM_REMOTE3_OPEN 0x0400 - -/* -- SENSORS SYSCTL END -- */ - - -static ctl_table lm83_dir_table_template[] = -{ - {LM83_SYSCTL_LOCAL_TEMP, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_temp}, - {LM83_SYSCTL_REMOTE1_TEMP, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_temp}, - {LM83_SYSCTL_REMOTE2_TEMP, "temp3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_temp}, - {LM83_SYSCTL_REMOTE3_TEMP, "temp4", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_temp}, - {LM83_SYSCTL_TCRIT, "tcrit", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_tcrit}, - {LM83_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_alarms}, - {0} -}; - -static ctl_table lm82_dir_table_template[] = -{ - {LM83_SYSCTL_LOCAL_TEMP, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_temp}, - {LM83_SYSCTL_REMOTE2_TEMP, "temp3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_temp}, - {LM83_SYSCTL_TCRIT, "tcrit", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_tcrit}, - {LM83_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm83_alarms}, - {0} -}; - -/* - * Real code - */ - -static int lm83_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, lm83_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int lm83_detect(struct i2c_adapter *adapter, int address, unsigned - short flags, int kind) -{ - struct i2c_client *new_client; - struct lm83_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) - { - printk("lm83.o: Called for an ISA bus adapter, aborting.\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - { -#ifdef DEBUG - printk("lm83.o: I2C bus doesn't support byte read mode, " - "skipping.\n"); -#endif - return 0; - } - - if (!(data = kmalloc(sizeof(struct lm83_data), GFP_KERNEL))) - { - printk("lm83.o: Out of memory in lm83_detect (new_client).\n"); - return -ENOMEM; - } - - /* - * The common I2C client data is placed right before the - * LM83-specific data. The LM83-specific data is pointed to by the - * data field from the I2C client data. - */ - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &lm83_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip (actually there is only - * one possible kind of chip for now, LM83). A zero kind means that - * the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - */ - - /* Default to an LM83 if forced */ - if (kind == 0) - kind = lm83; - - if (kind < 0) /* detection */ - { - if (((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS1) - & 0xA8) != 0x00) - || ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS2) - & 0x48) != 0x00) - || ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_CONFIG) - & 0x41) != 0x00)) - { -#ifdef DEBUG - printk(KERN_DEBUG "lm83.o: Detection failed at 0x%02x.\n", - address); -#endif - goto ERROR1; - } - } - - if (kind <= 0) /* identification */ - { - u8 man_id, chip_id; - - man_id = i2c_smbus_read_byte_data(new_client, LM83_REG_R_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, LM83_REG_R_CHIP_ID); - if (man_id == 0x01) /* National Semiconductor */ - { - if (chip_id == 0x03) - kind = lm83; - else if (chip_id == 0x01) - kind = lm82; - } - } - - if (kind <= 0) /* identification failed */ - { - printk("lm83.o: Unsupported chip.\n"); - goto ERROR1; - } - - if (kind == lm83) - { - type_name = "lm83"; - client_name = "LM83 chip"; - } - else if (kind == lm82) - { - type_name = "lm82"; - client_name = "LM82 chip"; - } - else - { - printk("lm83.o: Unknown kind %d.\n", kind); - goto ERROR1; - } - - /* - * OK, we got a valid chip so we can fill in the remaining client - * fields. - */ - - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* - * Tell the I2C layer a new client has arrived. - */ - - if ((err = i2c_attach_client(new_client))) - { -#ifdef DEBUG - printk("lm83.o: Failed attaching client.\n"); -#endif - goto ERROR1; - } - - /* - * Register a new directory entry. - */ - - if ((kind == lm83 && (err = i2c_register_entry(new_client, type_name, - lm83_dir_table_template, THIS_MODULE)) < 0) || - (kind == lm82 && (err = i2c_register_entry(new_client, type_name, - lm82_dir_table_template, THIS_MODULE)) < 0)) - { -#ifdef DEBUG - printk("lm83.o: Failed registering directory entry.\n"); -#endif - goto ERROR2; - } - data->sysctl_id = err; - - /* - * Initialize the LM83 chip - * (Nothing to do for this one.) - */ - - return 0; - - ERROR2: - i2c_detach_client(new_client); - ERROR1: - kfree(data); - return err; -} - -static int lm83_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct lm83_data *) (client->data))->sysctl_id); - if ((err = i2c_detach_client(client))) - { - printk("lm83.o: Client deregistration failed, client not " - "detached.\n"); - return err; - } - - kfree(client->data); - return 0; -} - -static void lm83_update_client(struct i2c_client *client) -{ - struct lm83_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ * 2) || - (jiffies < data->last_updated) || !data->valid) - { - int nr; -#ifdef DEBUG - printk("lm83.o: Updating LM83 data.\n"); -#endif - for (nr = 0; nr < 4 ; nr++) - { - data->temp[nr] = - i2c_smbus_read_byte_data(client, LM83_REG_R_TEMP[nr]); - data->temp_high[nr] = - i2c_smbus_read_byte_data(client, LM83_REG_R_HIGH[nr]); - } - data->tcrit = i2c_smbus_read_byte_data(client, LM83_REG_R_TCRIT); - data->alarms = - i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1) + - (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2) << 8); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -static void lm83_temp(struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results) -{ - struct lm83_data *data = client->data; - int nr = ctl_name - LM83_SYSCTL_LOCAL_TEMP; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) - { - lm83_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_high[nr]); - results[1] = TEMP_FROM_REG(data->temp[nr]); - *nrels_mag = 2; - } - else if (operation == SENSORS_PROC_REAL_WRITE) - { - if (*nrels_mag >= 1) - { - data->temp_high[nr] = TEMP_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, LM83_REG_W_HIGH[nr], - data->temp_high[nr]); - } - } -} - -static void lm83_tcrit(struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results) -{ - struct lm83_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) - { - lm83_update_client(client); - results[0] = TEMP_FROM_REG(data->tcrit); - *nrels_mag = 1; - } - else if (operation == SENSORS_PROC_REAL_WRITE) - { - if (*nrels_mag >= 1) - { - data->tcrit = TEMP_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, LM83_REG_W_TCRIT, - data->tcrit); - } - } -} - -static void lm83_alarms(struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results) -{ - struct lm83_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) - { - lm83_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -static int __init sm_lm83_init(void) -{ - printk(KERN_INFO "lm83.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&lm83_driver); -} - -static void __exit sm_lm83_exit(void) -{ - i2c_del_driver(&lm83_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("LM83 sensor driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_lm83_init); -module_exit(sm_lm83_exit); diff --git a/kernel/chips/lm85.c b/kernel/chips/lm85.c deleted file mode 100644 index 4f45e892..00000000 --- a/kernel/chips/lm85.c +++ /dev/null @@ -1,2037 +0,0 @@ -/* - lm85.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - Copyright (c) 2002, 2003 Philip Pokorny - Copyright (c) 2003 Margit Schubert-While - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - CHANGELOG - - 2002-11-13 First patch for LM85 functionality - 2002-11-18 LM85 functionality mostly done - 2002-12-02 Adding ADM1027 functionality - 2002-12-06 Adding ADT7463 functionality - 2003-01-09 Code cleanup. - Save reserved bits in case they are implemented - in a future chip. (Solve problem with lockups - on ADM1027 due to chip initialization) - Added chip initialization bypass option - 2003-02-12 Add THERM asserted counts for ADT7463 - Added #ifdef so we can compile against 2.6.5 - without updating i2c-ids.h - 2003-02-17 Prepare for switch to 2.7.0 development - Implement tmin_control for ADT7463 - Expose THERM asserted counts to /proc - Code cleanup - 2003-02-19 Working with Margit and LM_SENSORS developers - 2003-02-23 Removed chip initialization entirely - Scale voltages in driver at Margit's request - Change PWM from 0-100% to 0-255 per LM sensors standard - 2003-02-27 Documentation and code cleanups - Added this CHANGELOG - Print additional precision for temperatures and voltages - Many thanks to Margit Schubert-While and Brandt xxxxxx - for help testing this version - 2003-02-28 More diagnostic messages regarding BIOS setup - 2003-03-01 Added Interrupt mask register support. - 2003-03-08 Fixed problem with pseudo 16-bit registers - Cleaned up some compiler warnings. - Fixed problem with Operating Point and THERM counting - 2003-03-21 Initial support for EMC6D100 and EMC6D101 chips - 2003-06-30 Add support for EMC6D100 extra voltage inputs. -*/ - -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" - -#ifndef I2C_DRIVERID_LM85 -#define I2C_DRIVERID_LM85 1039 -#endif - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102); - -/* Many LM85 constants specified below */ - -/* The LM85 registers */ -#define LM85_REG_IN(nr) (0x20 + (nr)) -#define LM85_REG_IN_MIN(nr) (0x44 + (nr) * 2) -#define LM85_REG_IN_MAX(nr) (0x45 + (nr) * 2) - -#define LM85_REG_TEMP(nr) (0x25 + (nr)) -#define LM85_REG_TEMP_MIN(nr) (0x4e + (nr) * 2) -#define LM85_REG_TEMP_MAX(nr) (0x4f + (nr) * 2) - -/* Fan speeds are LSB, MSB (2 bytes) */ -#define LM85_REG_FAN(nr) (0x28 + (nr) *2) -#define LM85_REG_FAN_MIN(nr) (0x54 + (nr) *2) - -#define LM85_REG_PWM(nr) (0x30 + (nr)) - -#define ADT7463_REG_OPPOINT(nr) (0x33 + (nr)) - -#define ADT7463_REG_TMIN_CTL1 0x36 -#define ADT7463_REG_TMIN_CTL2 0x37 -#define ADT7463_REG_TMIN_CTL 0x0136 - -#define LM85_REG_DEVICE 0x3d -#define LM85_REG_COMPANY 0x3e -#define LM85_REG_VERSTEP 0x3f -/* These are the recognized values for the above regs */ -#define LM85_DEVICE_ADX 0x27 -#define LM85_COMPANY_NATIONAL 0x01 -#define LM85_COMPANY_ANALOG_DEV 0x41 -#define LM85_COMPANY_SMSC 0x5c -#define LM85_VERSTEP_VMASK 0xf0 -#define LM85_VERSTEP_SMASK 0x0f -#define LM85_VERSTEP_GENERIC 0x60 -#define LM85_VERSTEP_LM85C 0x60 -#define LM85_VERSTEP_LM85B 0x62 -#define LM85_VERSTEP_ADM1027 0x60 -#define LM85_VERSTEP_ADT7463 0x62 -#define LM85_VERSTEP_ADT7463C 0x6A -#define LM85_VERSTEP_EMC6D100_A0 0x60 -#define LM85_VERSTEP_EMC6D100_A1 0x61 -#define LM85_VERSTEP_EMC6D102 0x65 - -#define LM85_REG_CONFIG 0x40 - -#define LM85_REG_ALARM1 0x41 -#define LM85_REG_ALARM2 0x42 -#define LM85_REG_ALARM 0x0141 - -#define LM85_REG_VID 0x43 - -/* Automated FAN control */ -#define LM85_REG_AFAN_CONFIG(nr) (0x5c + (nr)) -#define LM85_REG_AFAN_RANGE(nr) (0x5f + (nr)) -#define LM85_REG_AFAN_SPIKE1 0x62 -#define LM85_REG_AFAN_SPIKE2 0x63 -#define LM85_REG_AFAN_MINPWM(nr) (0x64 + (nr)) -#define LM85_REG_AFAN_LIMIT(nr) (0x67 + (nr)) -#define LM85_REG_AFAN_CRITICAL(nr) (0x6a + (nr)) -#define LM85_REG_AFAN_HYST1 0x6d -#define LM85_REG_AFAN_HYST2 0x6e - -#define LM85_REG_TACH_MODE 0x74 -#define LM85_REG_SPINUP_CTL 0x75 - -#define ADM1027_REG_TEMP_OFFSET(nr) (0x70 + (nr)) -#define ADM1027_REG_CONFIG2 0x73 -#define ADM1027_REG_INTMASK1 0x74 -#define ADM1027_REG_INTMASK2 0x75 -#define ADM1027_REG_INTMASK 0x0174 -#define ADM1027_REG_EXTEND_ADC1 0x76 -#define ADM1027_REG_EXTEND_ADC2 0x77 -#define ADM1027_REG_EXTEND_ADC 0x0176 -#define ADM1027_REG_CONFIG3 0x78 -#define ADM1027_REG_FAN_PPR 0x7b - -#define ADT7463_REG_THERM 0x79 -#define ADT7463_REG_THERM_LIMIT 0x7A -#define ADT7463_REG_CONFIG4 0x7D - -#define EMC6D100_REG_SFR 0x7c -#define EMC6D100_REG_ALARM3 0x7d -#define EMC6D100_REG_CONF 0x7f -#define EMC6D100_REG_INT_EN 0x80 -/* IN5, IN6 and IN7 */ -#define EMC6D100_REG_IN(nr) (0x70 + ((nr)-5)) -#define EMC6D100_REG_IN_MIN(nr) (0x73 + ((nr)-5) * 2) -#define EMC6D100_REG_IN_MAX(nr) (0x74 + ((nr)-5) * 2) - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - */ - -/* IN are scaled 1.000 == 0xc0, mag = 3 */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val)*0xc0+500)/1000),0,255)) -#define INEXT_FROM_REG(val,ext) (((val)*1000 + (ext)*250 + 96)/0xc0) -#define IN_FROM_REG(val) (INEXT_FROM_REG(val,0)) - -/* IN are scaled acording to built-in resistors */ -static int lm85_scaling[] = { /* .001 Volts */ - 2500, 2250, 3300, 5000, 12000, - 3300, 1500, 1800, /* EMC6D100 */ - }; -#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from)) -#define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255)) -#define INSEXT_FROM_REG(n,val,ext) (SCALE((val)*4 + (ext),192*4,lm85_scaling[n])) -#define INS_FROM_REG(n,val) (INSEXT_FROM_REG(n,val,0)) - -/* FAN speed is measured using 90kHz clock */ -#define FAN_TO_REG(val) (SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534)) -#define FAN_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:5400000/(val)) - -/* Temperature is reported in .01 degC increments */ -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+50)/100,-127,127)) -#define TEMPEXT_FROM_REG(val,ext) ((val)*100 + (ext)*25) -#define TEMP_FROM_REG(val) (TEMPEXT_FROM_REG(val,0)) -#define EXTTEMP_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127)) -#define OPPOINT_TO_REG(val) (SENSORS_LIMIT(val,-127,127)) -#define OPPOINT_FROM_REG(val) (val) - -#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) -#define PWM_FROM_REG(val) (val) - -#define EXT_FROM_REG(val,sensor) (((val)>>(sensor * 2))&0x03) - -/* ZONEs have the following parameters: - * Limit (low) temp, 1. degC - * Hysteresis (below limit), 1. degC (0-15) - * Range of speed control, .1 degC (2-80) - * Critical (high) temp, 1. degC - * - * FAN PWMs have the following parameters: - * Reference Zone, 1, 2, 3, etc. - * Spinup time, .05 sec - * PWM value at limit/low temp, 1 count - * PWM Frequency, 1. Hz - * PWM is Min or OFF below limit, flag - * Invert PWM output, flag - * - * Some chips filter the temp, others the fan. - * Filter constant (or disabled) .1 seconds - */ - -/* These are the zone temperature range encodings */ -static int lm85_range_map[] = { /* .1 degC */ - 20, 25, 33, 40, 50, 66, - 80, 100, 133, 160, 200, 266, - 320, 400, 533, 800 - }; -static int RANGE_TO_REG( int range ) -{ - int i; - - if( range >= lm85_range_map[15] ) { return 15 ; } - for( i = 0 ; i < 15 ; ++i ) - if( range <= lm85_range_map[i] ) - break ; - return( i & 0x0f ); -} -#define RANGE_FROM_REG(val) (lm85_range_map[(val)&0x0f]) - -/* These are the Acoustic Enhancement, or Temperature smoothing encodings - * NOTE: The enable/disable bit is INCLUDED in these encodings as the - * MSB (bit 3, value 8). If the enable bit is 0, the encoded value - * is ignored, or set to 0. - */ -static int lm85_smooth_map[] = { /* .1 sec */ - 350, 176, 118, 70, 44, 30, 16, 8 -/* 35.4 * 1/1, 1/2, 1/3, 1/5, 1/8, 1/12, 1/24, 1/48 */ - }; -static int SMOOTH_TO_REG( int smooth ) -{ - int i; - - if( smooth <= 0 ) { return 0 ; } /* Disabled */ - for( i = 0 ; i < 7 ; ++i ) - if( smooth >= lm85_smooth_map[i] ) - break ; - return( (i & 0x07) | 0x08 ); -} -#define SMOOTH_FROM_REG(val) ((val)&0x08?lm85_smooth_map[(val)&0x07]:0) - -/* These are the fan spinup delay time encodings */ -static int lm85_spinup_map[] = { /* .1 sec */ - 0, 1, 2, 4, 7, 10, 20, 40 - }; -static int SPINUP_TO_REG( int spinup ) -{ - int i; - - if( spinup >= lm85_spinup_map[7] ) { return 7 ; } - for( i = 0 ; i < 7 ; ++i ) - if( spinup <= lm85_spinup_map[i] ) - break ; - return( i & 0x07 ); -} -#define SPINUP_FROM_REG(val) (lm85_spinup_map[(val)&0x07]) - -/* These are the PWM frequency encodings */ -static int lm85_freq_map[] = { /* .1 Hz */ - 100, 150, 230, 300, 380, 470, 620, 980 - }; -static int FREQ_TO_REG( int freq ) -{ - int i; - - if( freq >= lm85_freq_map[7] ) { return 7 ; } - for( i = 0 ; i < 7 ; ++i ) - if( freq <= lm85_freq_map[i] ) - break ; - return( i & 0x07 ); -} -#define FREQ_FROM_REG(val) (lm85_freq_map[(val)&0x07]) - -/* Since we can't use strings, I'm abusing these numbers - * to stand in for the following meanings: - * 1 -- PWM responds to Zone 1 - * 2 -- PWM responds to Zone 2 - * 3 -- PWM responds to Zone 3 - * 23 -- PWM responds to the higher temp of Zone 2 or 3 - * 123 -- PWM responds to highest of Zone 1, 2, or 3 - * 0 -- PWM is always at 0% (ie, off) - * -1 -- PWM is always at 100% - * -2 -- PWM responds to manual control - */ -static int lm85_zone_map[] = { 1, 2, 3, -1, 0, 23, 123, -2 }; -static int ZONE_TO_REG( int zone ) -{ - int i; - - for( i = 0 ; i <= 7 ; ++i ) - if( zone == lm85_zone_map[i] ) - break ; - if( i > 7 ) /* Not found. */ - i = 3; /* Always 100% */ - return( (i & 0x07)<<5 ); -} -#define ZONE_FROM_REG(val) (lm85_zone_map[((val)>>5)&0x07]) - -#define HYST_TO_REG(val) (SENSORS_LIMIT((-(val)+5)/10,0,15)) -#define HYST_FROM_REG(val) (-(val)*10) - -#define OFFSET_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127)) -#define OFFSET_FROM_REG(val) ((val)*25) - -#define PPR_MASK(fan) (0x03<<(fan *2)) -#define PPR_TO_REG(val,fan) (SENSORS_LIMIT((val)-1,0,3)<<(fan *2)) -#define PPR_FROM_REG(val,fan) ((((val)>>(fan * 2))&0x03)+1) - -/* When converting to REG, we need to fixup the carry-over bit */ -#define INTMASK_FROM_REG(val) (val) -#define INTMASK_TO_REG(val) (SENSORS_LIMIT((val)|((val)&0xff00?0x80:0),0,65535)) - -/* Typically used with Pentium 4 systems v9.1 VRM spec */ -#define LM85_INIT_VRM 91 - -/* Chip sampling rates - * - * Some sensors are not updated more frequently than once per second - * so it doesn't make sense to read them more often than that. - * We cache the results and return the saved data if the driver - * is called again before a second has elapsed. - * - * Also, there is significant configuration data for this chip - * given the automatic PWM fan control that is possible. There - * are about 47 bytes of config data to only 22 bytes of actual - * readings. So, we keep the config data up to date in the cache - * when it is written and only sample it once every 5 *minutes* - */ -#define LM85_DATA_INTERVAL (1 * HZ) -#define LM85_CONFIG_INTERVAL (5 * 60 * HZ) - -/* For each registered LM85, we need to keep some data in memory. That - data is pointed to by client->data. The structure itself is - dynamically allocated, when a new lm85 client is allocated. */ - -/* LM85 can automatically adjust fan speeds based on temperature - * This structure encapsulates an entire Zone config. There are - * three zones (one for each temperature input) on the lm85 - */ -struct lm85_zone { - s8 limit; /* Low temp limit */ - u8 hyst; /* Low limit hysteresis. (0-15) */ - u8 range; /* Temp range, encoded */ - s8 critical; /* "All fans ON" temp limit */ -}; - -struct lm85_autofan { - u8 config; /* Register value */ - u8 freq; /* PWM frequency, encoded */ - u8 min_pwm; /* Minimum PWM value, encoded */ - u8 min_off; /* Min PWM or OFF below "limit", flag */ -}; - -struct lm85_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - int valid; /* !=0 if following fields are valid */ - unsigned long last_reading; /* In jiffies */ - unsigned long last_config; /* In jiffies */ - - u8 in[8]; /* Register value */ - u8 in_max[8]; /* Register value */ - u8 in_min[8]; /* Register value */ - s8 temp[3]; /* Register value */ - s8 temp_min[3]; /* Register value */ - s8 temp_max[3]; /* Register value */ - s8 temp_offset[3]; /* Register value */ - u16 fan[4]; /* Register value */ - u16 fan_min[4]; /* Register value */ - u8 pwm[3]; /* Register value */ - u8 spinup_ctl; /* Register encoding, combined */ - u8 tach_mode; /* Register encoding, combined */ - u16 extend_adc; /* Register value */ - u8 fan_ppr; /* Register value */ - u8 smooth[3]; /* Register encoding */ - u8 vid; /* Register value */ - u8 vrm; /* VRM version */ - u8 syncpwm3; /* Saved PWM3 for TACH 2,3,4 config */ - s8 oppoint[3]; /* Register value */ - u16 tmin_ctl; /* Register value */ - long therm_total; /* Cummulative therm count */ - long therm_ovfl; /* Count of therm overflows */ - u8 therm_limit; /* Register value */ - u32 alarms; /* Register encoding, combined */ - u32 alarm_mask; /* Register encoding, combined */ - struct lm85_autofan autofan[3]; - struct lm85_zone zone[3]; -}; - -static int lm85_attach_adapter(struct i2c_adapter *adapter); -static int lm85_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int lm85_detach_client(struct i2c_client *client); -static int lm85_read_value(struct i2c_client *client, u16 register); -static int lm85_write_value(struct i2c_client *client, u16 register, int value); -static void lm85_update_client(struct i2c_client *client); -static void lm85_init_client(struct i2c_client *client); - - -static void lm85_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void lm85_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_zone(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_pwm_config(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_pwm_zone(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_smooth(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static void lm85_spinup_ctl(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm85_tach_mode(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static void adm1027_tach_mode(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1027_temp_offset(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1027_fan_ppr(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1027_alarm_mask(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static void adt7463_tmin_ctl(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adt7463_therm_signal(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static void emc6d100_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver lm85_driver = { - .name = "LM85 compatible sensor driver", - .id = I2C_DRIVERID_LM85, - .flags = I2C_DF_NOTIFY, - .attach_adapter = &lm85_attach_adapter, - .detach_client = &lm85_detach_client, -}; - -/* Unique ID assigned to each LM85 detected */ -static int lm85_id = 0; - -/* -- SENSORS SYSCTL START -- */ -/* Common parameters */ -#define LM85_SYSCTL_IN0 1000 -#define LM85_SYSCTL_IN1 1001 -#define LM85_SYSCTL_IN2 1002 -#define LM85_SYSCTL_IN3 1003 -#define LM85_SYSCTL_IN4 1004 -#define LM85_SYSCTL_FAN1 1005 -#define LM85_SYSCTL_FAN2 1006 -#define LM85_SYSCTL_FAN3 1007 -#define LM85_SYSCTL_FAN4 1008 -#define LM85_SYSCTL_TEMP1 1009 -#define LM85_SYSCTL_TEMP2 1010 -#define LM85_SYSCTL_TEMP3 1011 -#define LM85_SYSCTL_VID 1012 -#define LM85_SYSCTL_ALARMS 1013 -#define LM85_SYSCTL_PWM1 1014 -#define LM85_SYSCTL_PWM2 1015 -#define LM85_SYSCTL_PWM3 1016 -#define LM85_SYSCTL_VRM 1017 -#define LM85_SYSCTL_PWM_CFG1 1019 -#define LM85_SYSCTL_PWM_CFG2 1020 -#define LM85_SYSCTL_PWM_CFG3 1021 -#define LM85_SYSCTL_PWM_ZONE1 1022 -#define LM85_SYSCTL_PWM_ZONE2 1023 -#define LM85_SYSCTL_PWM_ZONE3 1024 -#define LM85_SYSCTL_ZONE1 1025 -#define LM85_SYSCTL_ZONE2 1026 -#define LM85_SYSCTL_ZONE3 1027 -#define LM85_SYSCTL_SMOOTH1 1028 -#define LM85_SYSCTL_SMOOTH2 1029 -#define LM85_SYSCTL_SMOOTH3 1030 - -/* Vendor specific values */ -#define LM85_SYSCTL_SPINUP_CTL 1100 -#define LM85_SYSCTL_TACH_MODE 1101 - -/* Analog Devices variant of the LM85 */ -#define ADM1027_SYSCTL_TACH_MODE 1200 -#define ADM1027_SYSCTL_TEMP_OFFSET1 1201 -#define ADM1027_SYSCTL_TEMP_OFFSET2 1202 -#define ADM1027_SYSCTL_TEMP_OFFSET3 1203 -#define ADM1027_SYSCTL_FAN_PPR 1204 -#define ADM1027_SYSCTL_ALARM_MASK 1205 - -/* Analog Devices variant of the LM85/ADM1027 */ -#define ADT7463_SYSCTL_TMIN_CTL1 1300 -#define ADT7463_SYSCTL_TMIN_CTL2 1301 -#define ADT7463_SYSCTL_TMIN_CTL3 1302 -#define ADT7463_SYSCTL_THERM_SIGNAL 1303 - -/* SMSC variant of the LM85 */ -#define EMC6D100_SYSCTL_IN5 1400 -#define EMC6D100_SYSCTL_IN6 1401 -#define EMC6D100_SYSCTL_IN7 1402 - -#define LM85_ALARM_IN0 0x0001 -#define LM85_ALARM_IN1 0x0002 -#define LM85_ALARM_IN2 0x0004 -#define LM85_ALARM_IN3 0x0008 -#define LM85_ALARM_TEMP1 0x0010 -#define LM85_ALARM_TEMP2 0x0020 -#define LM85_ALARM_TEMP3 0x0040 -#define LM85_ALARM_ALARM2 0x0080 -#define LM85_ALARM_IN4 0x0100 -#define LM85_ALARM_RESERVED 0x0200 -#define LM85_ALARM_FAN1 0x0400 -#define LM85_ALARM_FAN2 0x0800 -#define LM85_ALARM_FAN3 0x1000 -#define LM85_ALARM_FAN4 0x2000 -#define LM85_ALARM_TEMP1_FAULT 0x4000 -#define LM85_ALARM_TEMP3_FAULT 0x08000 -#define LM85_ALARM_IN6 0x10000 -#define LM85_ALARM_IN7 0x20000 -#define LM85_ALARM_IN5 0x40000 -/* -- SENSORS SYSCTL END -- */ - -/* The /proc/sys entries */ -/* These files are created for each detected LM85. This is just a template; - * The actual list is built from this and additional per-chip - * custom lists below. Note the XXX_LEN macros. These must be - * compile time constants because they will be used to allocate - * space for the final template passed to i2c_register_entry. - * We depend on the ability of GCC to evaluate expressions at - * compile time to turn these expressions into compile time - * constants, but this can generate a warning. - */ -static ctl_table lm85_common[] = { - {LM85_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_in}, - {LM85_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_in}, - {LM85_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_in}, - {LM85_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_in}, - {LM85_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_in}, - {LM85_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_fan}, - {LM85_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_fan}, - {LM85_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_fan}, - {LM85_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_fan}, - {LM85_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_temp}, - {LM85_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_temp}, - {LM85_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_temp}, - {LM85_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_vid}, - {LM85_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_vrm}, - {LM85_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_alarms}, - {LM85_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_pwm}, - {LM85_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_pwm}, - {LM85_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_pwm}, - {LM85_SYSCTL_PWM_CFG1, "pwm1_cfg", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_pwm_config}, - {LM85_SYSCTL_PWM_CFG2, "pwm2_cfg", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_pwm_config}, - {LM85_SYSCTL_PWM_CFG3, "pwm3_cfg", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_pwm_config}, - {LM85_SYSCTL_PWM_ZONE1, "pwm1_zone", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_pwm_zone}, - {LM85_SYSCTL_PWM_ZONE2, "pwm2_zone", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_pwm_zone}, - {LM85_SYSCTL_PWM_ZONE3, "pwm3_zone", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_pwm_zone}, - {LM85_SYSCTL_ZONE1, "zone1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_zone}, - {LM85_SYSCTL_ZONE2, "zone2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_zone}, - {LM85_SYSCTL_ZONE3, "zone3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_zone}, - {LM85_SYSCTL_SMOOTH1, "smooth1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_smooth}, - {LM85_SYSCTL_SMOOTH2, "smooth2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_smooth}, - {LM85_SYSCTL_SMOOTH3, "smooth3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm85_smooth}, - {0} -}; -#define CTLTBL_COMMON (sizeof(lm85_common)/sizeof(lm85_common[0])) - -/* NOTE: tach_mode is a shared name, but implemented with - * different functions - */ -static ctl_table lm85_specific[] = { - {LM85_SYSCTL_SPINUP_CTL, "spinup_ctl", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_spinup_ctl}, - {LM85_SYSCTL_TACH_MODE, "tach_mode", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm85_tach_mode}, -/* {0} The doc generator needs this. */ -}; -#define CTLTBL_LM85 (sizeof(lm85_specific)/sizeof(lm85_specific[0])) - -static ctl_table adm1027_specific[] = { - {ADM1027_SYSCTL_TACH_MODE, "tach_mode", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_tach_mode}, - {ADM1027_SYSCTL_TEMP_OFFSET1, "temp1_offset", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_temp_offset}, - {ADM1027_SYSCTL_TEMP_OFFSET2, "temp2_offset", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_temp_offset}, - {ADM1027_SYSCTL_TEMP_OFFSET3, "temp3_offset", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_temp_offset}, - {ADM1027_SYSCTL_FAN_PPR, "fan_ppr", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_fan_ppr}, - {ADM1027_SYSCTL_ALARM_MASK, "alarm_mask", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1027_alarm_mask}, -/* {0} The doc generator needs this. */ -}; -#define CTLTBL_ADM1027 (sizeof(adm1027_specific)/sizeof(adm1027_specific[0])) - -static ctl_table adt7463_specific[] = { - {ADT7463_SYSCTL_TMIN_CTL1, "tmin_ctl1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adt7463_tmin_ctl}, - {ADT7463_SYSCTL_TMIN_CTL2, "tmin_ctl2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adt7463_tmin_ctl}, - {ADT7463_SYSCTL_TMIN_CTL3, "tmin_ctl3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adt7463_tmin_ctl}, - {ADT7463_SYSCTL_THERM_SIGNAL, "therm_signal", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adt7463_therm_signal}, -/* {0} The doc generator needs this. */ -}; -#define CTLTBL_ADT7463 (sizeof(adt7463_specific)/sizeof(adt7463_specific[0])) - -static ctl_table emc6d100_specific[] = { - {EMC6D100_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &emc6d100_in}, - {EMC6D100_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &emc6d100_in}, - {EMC6D100_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &emc6d100_in}, -/* {0} The doc generator needs this. */ -}; -#define CTLTBL_EMC6D100 (sizeof(emc6d100_specific)/sizeof(emc6d100_specific[0])) - - -#define MAX2(a,b) ((a)>(b)?(a):(b)) -#define MAX3(a,b,c) ((a)>(b)?MAX2((a),(c)):MAX2((b),(c))) -#define MAX4(a,b,c,d) ((a)>(b)?MAX3((a),(c),(d)):MAX3((b),(c),(d))) - -#define CTLTBL_MAX (CTLTBL_COMMON + MAX3(CTLTBL_LM85, CTLTBL_ADM1027+CTLTBL_ADT7463, CTLTBL_EMC6D100)) - -/* This function is called when: - * lm85_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and lm85_driver is still present) */ -static int lm85_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, lm85_detect); -} - -/* This function is called by i2c_detect */ -static int lm85_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - int company, verstep ; - struct i2c_client *new_client; - struct lm85_data *data; - int err = 0; - const char *type_name = ""; - struct ctl_table template[CTLTBL_MAX] ; - int template_used ; - - if (i2c_is_isa_adapter(adapter)) { - /* This chip has no ISA interface */ - goto ERROR0 ; - }; - - if (!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BYTE_DATA)) { - /* We need to be able to do byte I/O */ - goto ERROR0 ; - }; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm85_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct lm85_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &lm85_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - company = lm85_read_value(new_client, LM85_REG_COMPANY); - verstep = lm85_read_value(new_client, LM85_REG_VERSTEP); - -#ifdef DEBUG - printk("lm85: Detecting device at %d,0x%02x with" - " COMPANY: 0x%02x and VERSTEP: 0x%02x\n", - i2c_adapter_id(new_client->adapter), new_client->addr, - company, verstep - ); -#endif - - /* If auto-detecting, Determine the chip type. */ - if (kind <= 0) { -#ifdef DEBUG - printk("lm85: Autodetecting device at %d,0x%02x ...\n", - i2c_adapter_id(adapter), address ); -#endif - if( company == LM85_COMPANY_NATIONAL - && verstep == LM85_VERSTEP_LM85C ) { - kind = lm85c ; - } else if( company == LM85_COMPANY_NATIONAL - && verstep == LM85_VERSTEP_LM85B ) { - kind = lm85b ; - } else if( company == LM85_COMPANY_NATIONAL - && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { - printk("lm85: Detected National Semiconductor chip\n"); - printk("lm85: Unrecgonized version/stepping 0x%02x" - " Defaulting to Generic LM85.\n", verstep ); - kind = any_chip ; - } else if( company == LM85_COMPANY_ANALOG_DEV - && verstep == LM85_VERSTEP_ADM1027 ) { - kind = adm1027 ; - } else if( company == LM85_COMPANY_ANALOG_DEV - && (verstep == LM85_VERSTEP_ADT7463 - || verstep == LM85_VERSTEP_ADT7463C) ) { - kind = adt7463 ; - } else if( company == LM85_COMPANY_ANALOG_DEV - && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { - printk("lm85: Detected Analog Devices chip\n"); - printk("lm85: Unrecgonized version/stepping 0x%02x" - " Defaulting to Generic LM85.\n", verstep ); - kind = any_chip ; - } else if( company == LM85_COMPANY_SMSC - && verstep == LM85_VERSTEP_EMC6D102) { - kind = emc6d102; - } else if( company == LM85_COMPANY_SMSC - && (verstep == LM85_VERSTEP_EMC6D100_A0 - || verstep == LM85_VERSTEP_EMC6D100_A1) ) { - /* Unfortunately, we can't tell a '100 from a '101 - * from the registers. Since a '101 is a '100 - * in a package with fewer pins and therefore no - * 3.3V, 1.5V or 1.8V inputs, perhaps if those - * inputs read 0, then it's a '101. - */ - kind = emc6d100 ; - } else if( company == LM85_COMPANY_SMSC - && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { - printk("lm85: Detected SMSC chip\n"); - printk("lm85: Unrecognized version/stepping 0x%02x" - " Defaulting to Generic LM85.\n", verstep ); - kind = any_chip ; - } else if( kind == any_chip - && (verstep & LM85_VERSTEP_VMASK) == LM85_VERSTEP_GENERIC) { - printk("lm85: Generic LM85 Version 6 detected\n"); - /* Leave kind as "any_chip" */ - } else { -#ifdef DEBUG - printk("lm85: Autodetection failed\n"); -#endif - /* Not an LM85 ... */ - if( kind == any_chip ) { /* User used force=x,y */ - printk("lm85: Generic LM85 Version 6 not" - " found at %d,0x%02x. Try force_lm85c.\n", - i2c_adapter_id(adapter), address ); - } - goto ERROR1; - } - } - - /* Fill in the chip specific driver values */ - switch (kind) { - case any_chip : - type_name = "lm85"; - strcpy(new_client->name, "Generic LM85"); - template_used = 0 ; - break ; - case lm85b : - type_name = "lm85b"; - strcpy(new_client->name, "National LM85-B"); - memcpy( template, lm85_specific, sizeof(lm85_specific) ); - template_used = CTLTBL_LM85 ; - break ; - case lm85c : - type_name = "lm85c"; - strcpy(new_client->name, "National LM85-C"); - memcpy( template, lm85_specific, sizeof(lm85_specific) ); - template_used = CTLTBL_LM85 ; - break ; - case adm1027 : - type_name = "adm1027"; - strcpy(new_client->name, "Analog Devices ADM1027"); - memcpy( template, adm1027_specific, sizeof(adm1027_specific) ); - template_used = CTLTBL_ADM1027 ; - break ; - case adt7463 : - type_name = "adt7463"; - strcpy(new_client->name, "Analog Devices ADT7463"); - memcpy( template, adt7463_specific, sizeof(adt7463_specific) ); - template_used = CTLTBL_ADT7463 ; - memcpy( template+template_used, adm1027_specific, sizeof(adm1027_specific) ); - template_used += CTLTBL_ADM1027 ; - break ; - case emc6d100 : - type_name = "emc6d100"; - strcpy(new_client->name, "SMSC EMC6D100"); - memcpy(template, emc6d100_specific, sizeof(emc6d100_specific)); - template_used = CTLTBL_EMC6D100 ; - break ; - case emc6d102 : - type_name = "emc6d102"; - strcpy(new_client->name, "SMSC EMC6D102"); - template_used = 0; - break; - default : - printk("lm85: Internal error, invalid kind (%d)!", kind); - err = -EFAULT ; - goto ERROR1; - } - - /* Fill in the remaining client fields */ - new_client->id = lm85_id++; - printk("lm85: Assigning ID %d to %s at %d,0x%02x\n", - new_client->id, new_client->name, - i2c_adapter_id(new_client->adapter), - new_client->addr - ); - - /* Housekeeping values */ - data->type = kind; - data->valid = 0; - - /* Set the VRM version */ - data->vrm = LM85_INIT_VRM ; - - /* Zero the accumulators */ - data->therm_total = 0; - data->therm_ovfl = 0; - - init_MUTEX(&data->update_lock); - - /* Initialize the LM85 chip */ - lm85_init_client(new_client); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR1; - - /* Finish out the template */ - memcpy( template + template_used, lm85_common, sizeof(lm85_common) ); - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR2; - } - data->sysctl_id = i; - - return 0; - - /* Error out and cleanup code */ - ERROR2: - i2c_detach_client(new_client); - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int lm85_detach_client(struct i2c_client *client) -{ - int err; - int id ; - - id = client->id; - i2c_deregister_entry(((struct lm85_data *)(client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("lm85(%d): Client deregistration failed," - " client not detached.\n", id ); - return err; - } - - kfree(client->data); - - return 0; -} - -static int lm85_read_value(struct i2c_client *client, u16 reg) -{ - int res; - - /* What size location is it? */ - switch( reg ) { - case LM85_REG_FAN(0) : /* Read WORD data */ - case LM85_REG_FAN(1) : - case LM85_REG_FAN(2) : - case LM85_REG_FAN(3) : - case LM85_REG_FAN_MIN(0) : - case LM85_REG_FAN_MIN(1) : - case LM85_REG_FAN_MIN(2) : - case LM85_REG_FAN_MIN(3) : - case LM85_REG_ALARM : /* Read ALARM1 and ALARM2 */ - case ADM1027_REG_INTMASK : /* Read MASK1 and MASK2 */ - case ADM1027_REG_EXTEND_ADC : /* Read ADC1 and ADC2 */ - reg &= 0xff ; /* Pseudo words have address + 0x0100 */ - res = i2c_smbus_read_byte_data(client, reg) & 0xff ; - res |= (i2c_smbus_read_byte_data(client, reg+1) & 0xff) << 8 ; - break ; - case ADT7463_REG_TMIN_CTL : /* Read WORD MSB, LSB */ - reg &= 0xff ; /* Pseudo words have address + 0x0100 */ - res = (i2c_smbus_read_byte_data(client, reg) & 0xff) << 8 ; - res |= i2c_smbus_read_byte_data(client, reg+1) & 0xff ; - break ; - default: /* Read BYTE data */ - res = i2c_smbus_read_byte_data(client, reg & 0xff) & 0xff ; - break ; - } - - return res ; -} - -static int lm85_write_value(struct i2c_client *client, u16 reg, int value) -{ - int res ; - - switch( reg ) { - case LM85_REG_FAN(0) : /* Write WORD data */ - case LM85_REG_FAN(1) : - case LM85_REG_FAN(2) : - case LM85_REG_FAN(3) : - case LM85_REG_FAN_MIN(0) : - case LM85_REG_FAN_MIN(1) : - case LM85_REG_FAN_MIN(2) : - case LM85_REG_FAN_MIN(3) : - case ADM1027_REG_INTMASK : - /* NOTE: ALARM and ADC are read only, so not included here */ - reg &= 0xff ; /* Pseudo words have address + 0x0100 */ - res = i2c_smbus_write_byte_data(client, reg, value & 0xff) ; - res |= i2c_smbus_write_byte_data(client, reg+1, (value>>8) & 0xff) ; - break ; - case ADT7463_REG_TMIN_CTL : /* Write WORD MSB, LSB */ - reg &= 0xff ; /* Pseudo words have address + 0x0100 */ - res = i2c_smbus_write_byte_data(client, reg, (value>>8) & 0xff); - res |= i2c_smbus_write_byte_data(client, reg+1, value & 0xff) ; - break ; - default: /* Write BYTE data */ - res = i2c_smbus_write_byte_data(client, reg & 0xff, value); - break ; - } - - return res ; -} - -/* Called when we have found a new LM85. */ -static void lm85_init_client(struct i2c_client *client) -{ - int value; - struct lm85_data *data = client->data; - -#ifdef DEBUG - printk("lm85(%d): Initializing device\n", client->id); -#endif - - /* Warn if part was not "READY" */ - value = lm85_read_value(client, LM85_REG_CONFIG); -#ifdef DEBUG - printk("lm85(%d): LM85_REG_CONFIG is: 0x%02x\n", client->id, value ); -#endif - if( value & 0x02 ) { - printk("lm85(%d): Client (%d,0x%02x) config is locked.\n", - client->id, - i2c_adapter_id(client->adapter), client->addr ); - }; - if( ! (value & 0x04) ) { - printk("lm85(%d): Client (%d,0x%02x) is not ready.\n", - client->id, - i2c_adapter_id(client->adapter), client->addr ); - }; - if( (data->type == adm1027 || data->type == adt7463) - && (value & 0x10) - ) { - printk("lm85(%d): Client (%d,0x%02x) VxI mode is set. " - "Please report this to the lm85 maintainer.\n", - client->id, - i2c_adapter_id(client->adapter), client->addr ); - }; - - /* See if SYNC to PWM3 is set */ - if( data->type == adt7463 - && (lm85_read_value(client, LM85_REG_AFAN_SPIKE1) & 0x10) - ) { - printk("lm85(%d): Sync to PWM3 is set. Expect PWM3 " - "to control fans 2, 3, and 4\n", - client->id ); - }; - - /* See if PWM2 is #SMBALERT */ - if( (data->type == adm1027 || data->type == adt7463) - && (lm85_read_value(client, ADM1027_REG_CONFIG3) & 0x01) - ) { - printk("lm85(%d): PWM2 is SMBALERT. PWM2 not available.\n", - client->id ); - }; - - /* Check if 2.5V and 5V inputs are reconfigured */ - if( data->type == adt7463 ) { - value = lm85_read_value(client, ADT7463_REG_CONFIG4); - if( value & 0x01 ) { - printk("lm85(%d): 2.5V input (in0) is SMBALERT. " - "in0 not available.\n", client->id ); - }; - if( value & 0x02 ) { - printk("lm85(%d): 5V input (in3) is THERM. " - "in3 not available.\n", client->id ); - } - }; - - /* FIXME? Display EMC6D100 config info? */ - - /* WE INTENTIONALLY make no changes to the limits, - * offsets, pwms, fans and zones. If they were - * configured, we don't want to mess with them. - * If they weren't, the default is 100% PWM, no - * control and will suffice until 'sensors -s' - * can be run by the user. - */ - - /* Start monitoring */ - value = lm85_read_value(client, LM85_REG_CONFIG); - /* Try to clear LOCK, Set START, save everything else */ - value = ((value & ~ 0x02) | 0x01) & 0xff ; -#ifdef DEBUG - printk("lm85(%d): Setting CONFIG to: 0x%02x\n", client->id, value ); -#endif - lm85_write_value(client, LM85_REG_CONFIG, value); - -} - -static void lm85_update_client(struct i2c_client *client) -{ - struct lm85_data *data = client->data; - int i; - - down(&data->update_lock); - - if (!data->valid - || (jiffies - data->last_reading > LM85_DATA_INTERVAL )) { - /* Things that change quickly */ - -#ifdef DEBUG - printk("lm85(%d): Reading sensor values\n", client->id); -#endif - /* Have to read extended bits first to "freeze" the - * more significant bits that are read later. - */ - switch( data->type ) { - case adm1027 : - case adt7463 : - data->extend_adc = - lm85_read_value(client, ADM1027_REG_EXTEND_ADC); - break ; - default : - data->extend_adc = 0 ; - break ; - } - - for (i = 0; i <= 4; ++i) { - data->in[i] = - lm85_read_value(client, LM85_REG_IN(i)); - } - - for (i = 0; i <= 3; ++i) { - data->fan[i] = - lm85_read_value(client, LM85_REG_FAN(i)); - } - - for (i = 0; i <= 2; ++i) { - data->temp[i] = - lm85_read_value(client, LM85_REG_TEMP(i)); - } - - for (i = 0; i <= 2; ++i) { - data->pwm[i] = - lm85_read_value(client, LM85_REG_PWM(i)); - } - - data->alarms = lm85_read_value(client, LM85_REG_ALARM); - - switch( ((struct lm85_data *)(client->data))->type ) { - case adt7463 : - /* REG_THERM code duplicated in therm_signal() */ - i = lm85_read_value(client, ADT7463_REG_THERM); - if( data->therm_total < LONG_MAX - 256 ) { - data->therm_total += i ; - } - if( i >= 255 ) { - ++data->therm_ovfl ; - } - break ; - case emc6d100 : - /* Three more voltage sensors */ - for (i = 5; i <= 7; ++i) { - data->in[i] = - lm85_read_value(client, EMC6D100_REG_IN(i)); - } - /* More alarm bits */ - data->alarms |= - lm85_read_value(client, EMC6D100_REG_ALARM3) << 16; - - break ; - default : break ; /* no warnings */ - } - - data->last_reading = jiffies ; - }; /* last_reading */ - - if (!data->valid - || (jiffies - data->last_config > LM85_CONFIG_INTERVAL) ) { - /* Things that don't change often */ - -#ifdef DEBUG - printk("lm85(%d): Reading config values\n", client->id); -#endif - for (i = 0; i <= 4; ++i) { - data->in_min[i] = - lm85_read_value(client, LM85_REG_IN_MIN(i)); - data->in_max[i] = - lm85_read_value(client, LM85_REG_IN_MAX(i)); - } - - for (i = 0; i <= 3; ++i) { - data->fan_min[i] = - lm85_read_value(client, LM85_REG_FAN_MIN(i)); - } - - for (i = 0; i <= 2; ++i) { - data->temp_min[i] = - lm85_read_value(client, LM85_REG_TEMP_MIN(i)); - data->temp_max[i] = - lm85_read_value(client, LM85_REG_TEMP_MAX(i)); - } - - data->vid = lm85_read_value(client, LM85_REG_VID); - - for (i = 0; i <= 2; ++i) { - int val ; - data->autofan[i].config = - lm85_read_value(client, LM85_REG_AFAN_CONFIG(i)); - val = lm85_read_value(client, LM85_REG_AFAN_RANGE(i)); - data->autofan[i].freq = val & 0x07 ; - data->zone[i].range = (val >> 4) & 0x0f ; - data->autofan[i].min_pwm = - lm85_read_value(client, LM85_REG_AFAN_MINPWM(i)); - data->zone[i].limit = - lm85_read_value(client, LM85_REG_AFAN_LIMIT(i)); - data->zone[i].critical = - lm85_read_value(client, LM85_REG_AFAN_CRITICAL(i)); - } - - i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1); - data->smooth[0] = i & 0x0f ; - data->syncpwm3 = i & 0x10 ; /* Save PWM3 config */ - data->autofan[0].min_off = i & 0x20 ; - data->autofan[1].min_off = i & 0x40 ; - data->autofan[2].min_off = i & 0x80 ; - i = lm85_read_value(client, LM85_REG_AFAN_SPIKE2); - data->smooth[1] = (i>>4) & 0x0f ; - data->smooth[2] = i & 0x0f ; - - i = lm85_read_value(client, LM85_REG_AFAN_HYST1); - data->zone[0].hyst = (i>>4) & 0x0f ; - data->zone[1].hyst = i & 0x0f ; - - i = lm85_read_value(client, LM85_REG_AFAN_HYST2); - data->zone[2].hyst = (i>>4) & 0x0f ; - - switch( ((struct lm85_data *)(client->data))->type ) { - case lm85b : - case lm85c : - data->tach_mode = lm85_read_value(client, - LM85_REG_TACH_MODE ); - data->spinup_ctl = lm85_read_value(client, - LM85_REG_SPINUP_CTL ); - break ; - case adt7463 : - for (i = 0; i <= 2; ++i) { - data->oppoint[i] = lm85_read_value(client, - ADT7463_REG_OPPOINT(i) ); - } - data->tmin_ctl = lm85_read_value(client, - ADT7463_REG_TMIN_CTL ); - data->therm_limit = lm85_read_value(client, - ADT7463_REG_THERM_LIMIT ); - /* FALL THROUGH */ - case adm1027 : - for (i = 0; i <= 2; ++i) { - data->temp_offset[i] = lm85_read_value(client, - ADM1027_REG_TEMP_OFFSET(i) ); - } - data->tach_mode = lm85_read_value(client, - ADM1027_REG_CONFIG3 ); - data->fan_ppr = lm85_read_value(client, - ADM1027_REG_FAN_PPR ); - data->alarm_mask = lm85_read_value(client, - ADM1027_REG_INTMASK ); - break ; - case emc6d100 : - for (i = 5; i <= 7; ++i) { - data->in_min[i] = - lm85_read_value(client, EMC6D100_REG_IN_MIN(i)); - data->in_max[i] = - lm85_read_value(client, EMC6D100_REG_IN_MAX(i)); - } - break ; - default : break ; /* no warnings */ - } - - data->last_config = jiffies; - }; /* last_config */ - - data->valid = 1; - - up(&data->update_lock); -} - - -/* The next functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the data - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - */ -void lm85_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - LM85_SYSCTL_IN0; - - if (nr < 0 || nr > 4) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; /* 1.000 */ - else if (operation == SENSORS_PROC_REAL_READ) { - int ext = 0 ; - lm85_update_client(client); - ext = EXT_FROM_REG(data->extend_adc, nr); - results[0] = INS_FROM_REG(nr,data->in_min[nr]); - results[1] = INS_FROM_REG(nr,data->in_max[nr]); - results[2] = INSEXT_FROM_REG(nr,data->in[nr],ext); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 1) { - data->in_max[nr] = INS_TO_REG(nr,results[1]); - lm85_write_value(client, LM85_REG_IN_MAX(nr), - data->in_max[nr]); - } - if (*nrels_mag > 0) { - data->in_min[nr] = INS_TO_REG(nr,results[0]); - lm85_write_value(client, LM85_REG_IN_MIN(nr), - data->in_min[nr]); - } - up(&data->update_lock); - } -} - -void lm85_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - LM85_SYSCTL_FAN1 ; - - if (nr < 0 || nr > 3) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr]); - results[1] = FAN_FROM_REG(data->fan[nr]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->fan_min[nr] = FAN_TO_REG(results[0]); - lm85_write_value(client, LM85_REG_FAN_MIN(nr), - data->fan_min[nr]); - } - up(&data->update_lock); - } -} - - -void lm85_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - LM85_SYSCTL_TEMP1 ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - int ext = 0 ; - lm85_update_client(client); - - /* +5 for offset of temp data in ext reg */ - ext = EXT_FROM_REG(data->extend_adc, nr+5); - - results[0] = TEMP_FROM_REG(data->temp_min[nr]); - results[1] = TEMP_FROM_REG(data->temp_max[nr]); - results[2] = TEMPEXT_FROM_REG(data->temp[nr],ext); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 1) { - data->temp_max[nr] = TEMP_TO_REG(results[1]); - lm85_write_value(client, LM85_REG_TEMP_MAX(nr), - data->temp_max[nr]); - } - if (*nrels_mag > 0) { - data->temp_min[nr] = TEMP_TO_REG(results[0]); - lm85_write_value(client, LM85_REG_TEMP_MIN(nr), - data->temp_min[nr]); - } - up(&data->update_lock); - } -} - -void lm85_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - LM85_SYSCTL_PWM1 ; - int pwm_zone ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = PWM_FROM_REG(data->pwm[nr]); - pwm_zone = ZONE_FROM_REG(data->autofan[nr].config); - /* PWM "enabled" if not off (0) nor on (-1) */ - results[1] = pwm_zone != 0 && pwm_zone != -1 ; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - /* PWM enable is read-only */ - if (*nrels_mag > 0) { - data->pwm[nr] = PWM_TO_REG(results[0]); - lm85_write_value(client, LM85_REG_PWM(nr), - data->pwm[nr]); - } - up(&data->update_lock); - } -} - -void lm85_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - - if( ctl_name != LM85_SYSCTL_VID ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = vid_from_reg((data->vid)&0x3f, data->vrm); - *nrels_mag = 1; - } -} - -void lm85_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - - if( ctl_name != LM85_SYSCTL_VRM ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm ; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->vrm = results[0] ; - } - up(&data->update_lock); - } -} - -void lm85_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - - if( ctl_name != LM85_SYSCTL_ALARMS ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -void lm85_spinup_ctl(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int old; - - if( ctl_name != LM85_SYSCTL_SPINUP_CTL ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = (data->spinup_ctl & 1) != 0 ; - results[1] = (data->spinup_ctl & 2) != 0 ; - results[2] = (data->spinup_ctl & 4) != 0 ; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - old = data->spinup_ctl ; - if (*nrels_mag > 2) { - old = (old & (~4)) | (results[2]?4:0) ; - } - if (*nrels_mag > 1) { - old = (old & (~2)) | (results[1]?2:0) ; - } - if (*nrels_mag > 0) { - old = (old & (~1)) | (results[0]?1:0) ; - lm85_write_value(client, LM85_REG_SPINUP_CTL, old); - data->spinup_ctl = old ; - } - up(&data->update_lock); - } -} - -void lm85_tach_mode(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int old; - - /* Tach Mode 1, Tach Mode 2, Tach Mode 3 & 4 */ - - if( ctl_name != LM85_SYSCTL_TACH_MODE ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = (data->tach_mode & 0x03) ; - results[1] = (data->tach_mode & 0x0c) >> 2 ; - results[2] = (data->tach_mode & 0x30) >> 4 ; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - old = data->tach_mode ; - if (*nrels_mag > 2) { - old = (old & (~0x30)) | ((results[2]&3) << 4) ; - } - if (*nrels_mag > 1) { - old = (old & (~0x0c)) | ((results[1]&3) << 2) ; - } - if (*nrels_mag > 0) { - old = (old & (~0x03)) | (results[0]&3) ; - lm85_write_value(client, LM85_REG_TACH_MODE, old); - data->tach_mode = old ; - } - up(&data->update_lock); - } -} - -void adm1027_tach_mode(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int old; - - /* Tach/DC 1, Tach/DC 2, Tach/DC 3, Tach/DC 4 */ - - if( ctl_name != ADM1027_SYSCTL_TACH_MODE ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = (data->tach_mode & 0x10) != 0 ; - results[1] = (data->tach_mode & 0x20) != 0 ; - results[2] = (data->tach_mode & 0x40) != 0 ; - results[3] = (data->tach_mode & 0x80) != 0 ; - *nrels_mag = 4; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - old = data->tach_mode ; - if (*nrels_mag > 3) { - old = (old & (~0x80)) | (results[3] ? 0x80 : 0) ; - } - if (*nrels_mag > 2) { - old = (old & (~0x40)) | (results[2] ? 0x40 : 0) ; - } - if (*nrels_mag > 1) { - old = (old & (~0x20)) | (results[1] ? 0x20 : 0) ; - } - if (*nrels_mag > 0) { - old = (old & (~0x10)) | (results[0] ? 0x10 : 0) ; - - /* Enable fast measurements if any TACH's are DC */ - old = (old & (~0x08)) | ((old&0xf0) ? 0x08 : 0) ; - - lm85_write_value(client, ADM1027_REG_CONFIG3, old); - data->tach_mode = old ; - } - up(&data->update_lock); - } -} - -void lm85_pwm_config(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - LM85_SYSCTL_PWM_CFG1 ; - - /* Spinup, min PWM, PWM Frequency, min below limit, Invert */ - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - - results[0] = SPINUP_FROM_REG(data->autofan[nr].config); - results[1] = PWM_FROM_REG(data->autofan[nr].min_pwm)*10; - results[2] = FREQ_FROM_REG(data->autofan[nr].freq); - results[3] = data->autofan[nr].min_off ? 10 : 0 ; - results[4] = (data->autofan[nr].config & 0x10) ? 10 : 0 ; - *nrels_mag = 5; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - int old_config ; - - down(&data->update_lock); - old_config = data->autofan[nr].config ; - if (*nrels_mag > 4) { - old_config = (old_config & (~0x10)) | (results[4]?0x10:0) ; - } - if (*nrels_mag > 3) { - data->autofan[nr].min_off = results[3] != 0 ; - lm85_write_value(client, LM85_REG_AFAN_SPIKE1, - data->smooth[0] - | data->syncpwm3 - | (data->autofan[0].min_off ? 0x20 : 0) - | (data->autofan[1].min_off ? 0x40 : 0) - | (data->autofan[2].min_off ? 0x80 : 0) - ); - } - if (*nrels_mag > 2) { - data->autofan[nr].freq = FREQ_TO_REG(results[2]) ; - lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), - (data->zone[nr].range << 4) - | data->autofan[nr].freq - ); - } - if (*nrels_mag > 1) { - data->autofan[nr].min_pwm = PWM_TO_REG((results[1]+5)/10); - lm85_write_value(client, LM85_REG_AFAN_MINPWM(nr), - data->autofan[nr].min_pwm - ); - } - if (*nrels_mag > 0) { - old_config = (old_config & (~0x07)) | SPINUP_TO_REG(results[0]) ; - lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr), old_config); - data->autofan[nr].config = old_config ; - } - up(&data->update_lock); - } -} - -void lm85_smooth(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - LM85_SYSCTL_SMOOTH1 ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = SMOOTH_FROM_REG(data->smooth[nr]); - *nrels_mag = 1; - - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if( *nrels_mag > 0 ) { - data->smooth[nr] = SMOOTH_TO_REG(results[0]); - } - if( nr == 0 ) { - lm85_write_value(client, LM85_REG_AFAN_SPIKE1, - data->smooth[0] - | data->syncpwm3 - | (data->autofan[0].min_off ? 0x20 : 0) - | (data->autofan[1].min_off ? 0x40 : 0) - | (data->autofan[2].min_off ? 0x80 : 0) - ); - } else { - lm85_write_value(client, LM85_REG_AFAN_SPIKE2, - (data->smooth[1] << 4) | data->smooth[2]); - } - up(&data->update_lock); - } -} - -void lm85_zone(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - LM85_SYSCTL_ZONE1 ; - - /* Limit, Hysteresis (neg), Range, Critical */ - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - - results[0] = TEMP_FROM_REG(data->zone[nr].limit) / 10; - results[1] = HYST_FROM_REG(data->zone[nr].hyst); - results[2] = RANGE_FROM_REG(data->zone[nr].range); - results[3] = TEMP_FROM_REG(data->zone[nr].critical) / 10; - *nrels_mag = 4; - - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 3) { - data->zone[nr].critical = TEMP_TO_REG(results[3]*10); - lm85_write_value(client, LM85_REG_AFAN_CRITICAL(nr), - data->zone[nr].critical ); - } - if (*nrels_mag > 2) { - data->zone[nr].range = RANGE_TO_REG(results[2]); - lm85_write_value(client, LM85_REG_AFAN_RANGE(nr), - (data->zone[nr].range << 4) - | data->autofan[nr].freq - ); - } - if (*nrels_mag > 1) { - data->zone[nr].hyst = HYST_TO_REG(results[1]); - if( nr == 0 || nr == 1 ) { - lm85_write_value(client, LM85_REG_AFAN_HYST1, - (data->zone[0].hyst << 4) - | data->zone[1].hyst - ); - } else { - lm85_write_value(client, LM85_REG_AFAN_HYST2, - (data->zone[2].hyst << 4) - ); - } - } - if (*nrels_mag > 0) { - data->zone[nr].limit = TEMP_TO_REG(results[0]*10); - lm85_write_value(client, LM85_REG_AFAN_LIMIT(nr), - data->zone[nr].limit - ); - } - up(&data->update_lock); - } -} - -void lm85_pwm_zone(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - LM85_SYSCTL_PWM_ZONE1 ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = ZONE_FROM_REG(data->autofan[nr].config); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->autofan[nr].config = - (data->autofan[nr].config & (~0xe0)) - | ZONE_TO_REG(results[0]) ; - lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr), - data->autofan[nr].config); - } - up(&data->update_lock); - } -} - -void adm1027_temp_offset(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - ADM1027_SYSCTL_TEMP_OFFSET1 ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - switch( data->type ) { - case adm1027 : - default : - results[0] = TEMP_FROM_REG(data->temp_offset[nr]); - break ; - case adt7463 : - results[0] = TEMPEXT_FROM_REG(0,data->temp_offset[nr]); - break ; - } - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - switch( data->type ) { - case adm1027 : - default : - data->temp_offset[nr] = TEMP_TO_REG(results[0]); - break ; - case adt7463 : - data->temp_offset[nr] = EXTTEMP_TO_REG(results[0]); - break ; - }; - lm85_write_value(client, ADM1027_REG_TEMP_OFFSET(nr), - data->temp_offset[nr]); - } - up(&data->update_lock); - } -} - -void adm1027_fan_ppr(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int old ; - - if (ctl_name != ADM1027_SYSCTL_FAN_PPR) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = PPR_FROM_REG(data->fan_ppr,0); - results[1] = PPR_FROM_REG(data->fan_ppr,1); - results[2] = PPR_FROM_REG(data->fan_ppr,2); - results[3] = PPR_FROM_REG(data->fan_ppr,3); - *nrels_mag = 4; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - old = data->fan_ppr ; - if (*nrels_mag > 3) { - old = (old & ~PPR_MASK(3)) | PPR_TO_REG(results[3],3); - }; - if (*nrels_mag > 2) { - old = (old & ~PPR_MASK(2)) | PPR_TO_REG(results[2],2); - }; - if (*nrels_mag > 1) { - old = (old & ~PPR_MASK(1)) | PPR_TO_REG(results[1],1); - }; - if (*nrels_mag > 0) { - old = (old & ~PPR_MASK(0)) | PPR_TO_REG(results[0],0); - lm85_write_value(client, ADM1027_REG_FAN_PPR, old); - data->fan_ppr = old ; - } - up(&data->update_lock); - } -} - -void adm1027_alarm_mask(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - - if( ctl_name != ADM1027_SYSCTL_ALARM_MASK ) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = INTMASK_FROM_REG(data->alarm_mask); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 0) { - data->alarm_mask = INTMASK_TO_REG(results[0]); - lm85_write_value(client, ADM1027_REG_INTMASK, - data->alarm_mask); - } - up(&data->update_lock); - } -} - -void adt7463_tmin_ctl(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - ADT7463_SYSCTL_TMIN_CTL1 ; - u16 old ; - - if (nr < 0 || nr > 2) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - old = data->tmin_ctl ; - results[0] = (old & ( 0x2000 << nr )) != 0 ; - results[1] = (old >> (nr*3)) & 0x07 ; - results[2] = (old & ( 0x0400 << nr )) != 0 ; - results[3] = OPPOINT_FROM_REG(data->oppoint[nr]); - *nrels_mag = 4; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - old = data->tmin_ctl ; - if (*nrels_mag > 3) { - data->oppoint[nr] = OPPOINT_TO_REG(results[3]); - lm85_write_value(client, ADT7463_REG_OPPOINT(nr), - data->oppoint[nr]); - }; - if (*nrels_mag > 2) { - if( results[2] ) { - old |= (0x0400 << nr) ; - } else { - old &= ~(0x0400 << nr) ; - } - }; - if (*nrels_mag > 1) { - old &= ~(0x07 << (nr*3)) ; - old |= (results[1] & 0x07) << (nr*3) ; - }; - if (*nrels_mag > 0) { - if( results[0] ) { - old |= 0x2000 << nr ; - } else { - old &= ~(0x2000 << nr) ; - } - lm85_write_value(client, ADT7463_REG_TMIN_CTL, old); - data->tmin_ctl = old ; - } - up(&data->update_lock); - } -} - -void adt7463_therm_signal(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int counts ; - - if (ctl_name != ADT7463_SYSCTL_THERM_SIGNAL) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - /* Don't call update_client here because - * ADT7463_REG_THERM has to be read every - * 5 seconds to prevent lost counts - */ - down(&data->update_lock); - counts = lm85_read_value(client, ADT7463_REG_THERM) & 0xff; - if( data->therm_total < LONG_MAX - 256 ) { - data->therm_total += counts ; - } - if( counts >= 255 ) { - ++data->therm_ovfl ; - } - up(&data->update_lock); - - results[0] = data->therm_limit ; - results[1] = data->therm_total ; - results[2] = data->therm_ovfl ; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - /* therm_total and therm_ovfl are read only */ - if (*nrels_mag > 0) { - data->therm_limit = SENSORS_LIMIT(results[0],0,255); - lm85_write_value(client, ADT7463_REG_THERM_LIMIT, - data->therm_limit); - }; - up(&data->update_lock); - } -} - - -void emc6d100_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm85_data *data = client->data; - int nr = ctl_name - EMC6D100_SYSCTL_IN5 +5; - - if (nr < 5 || nr > 7) - return ; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; /* 1.000 */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm85_update_client(client); - results[0] = INS_FROM_REG(nr,data->in_min[nr]); - results[1] = INS_FROM_REG(nr,data->in_max[nr]); - results[2] = INS_FROM_REG(nr,data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag > 1) { - data->in_max[nr] = INS_TO_REG(nr,results[1]); - lm85_write_value(client, EMC6D100_REG_IN_MAX(nr), - data->in_max[nr]); - } - if (*nrels_mag > 0) { - data->in_min[nr] = INS_TO_REG(nr,results[0]); - lm85_write_value(client, EMC6D100_REG_IN_MIN(nr), - data->in_min[nr]); - } - up(&data->update_lock); - } -} - - -static int __init sm_lm85_init(void) -{ - printk("lm85: Version %s (%s)\n", LM_VERSION, LM_DATE); - printk("lm85: See http://www.penguincomputing.com/lm_sensors for more info.\n" ); - return i2c_add_driver(&lm85_driver); -} - -static void __exit sm_lm85_exit(void) -{ - i2c_del_driver(&lm85_driver); -} - -/* Thanks to Richard Barrington for adding the LM85 to sensors-detect. - * Thanks to Margit Schubert-While for help with - * post 2.7.0 CVS changes - */ -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Philip Pokorny - Philip Edelbrock - Stephen Rousset - Dan Eaton - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - - -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" - -/* Chip configuration settings. These should be set to reflect the -HARDWARE configuration of your chip. By default (read: when all of -these are left commented out), this driver assumes that the -configuration is the same as National's defaults for the Channel Mode -register. - -Set to '1' the appropriate defines, as nessesary: - - - External temp sensors 2 (possible second CPU temp) - This will disable the 2.5V and Vccp2 readings. - Ironically, National decided that you can read the - temperature of a second CPU or it's core voltage, - but not both! Comment out if FAULT is reported. */ - -/* #define LM87_EXT2 1 */ - -/* Aux analog input. When enabled, the Fan 1 reading - will be disabled */ - -/* #define LM87_AIN1 1 */ - -/* Aux analog input 2. When enabled, the Fan 2 reading - will be disabled */ - -/* #define LM87_AIN2 1 */ - -/* Internal Vcc is 5V instead of 3.3V */ - -/* #define LM87_5V_VCC 1 */ - -/* That's the end of the hardware config defines. I would have made - them insmod params, but it would be too much work. ;') */ - - - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(lm87); - -/* The following is the calculation for the register offset - * for the monitored items minimum and maximum locations. - */ -#define LM87_REG_IN_MAX(nr) (0x2b + ((nr) * 2)) -#define LM87_REG_IN_MIN(nr) (0x2c + ((nr) * 2)) -#define LM87_REG_IN(nr) (0x20 + (nr)) - -/* Initial limits */ - -/* - * LM87 register definition - * - */ - - /* The LM87 registers */ -#define LM87_INT_TEMP_HI_LIMIT_LOCKABLE 0x13 -#define LM87_EXT_TEMP_HI_LIMIT_LOCKABLE 0x14 -#define LM87_REG_TEST 0x15 -#define LM87_REG_CHANNEL_MODE 0x16 -#define LM87_REG_INT_TEMP_HI_LIMIT 0x17 -#define LM87_REG_EXT_TEMP_HI_LIMIT 0x18 -#define LM87_REG_ANALOG_OUT 0x19 - - /* These are all read-only */ -#define LM87_REG_2_5V_EXT_TEMP_2 0x20 -#define LM87_REG_VCCP1 0x21 -#define LM87_REG_3_3V 0x22 -#define LM87_REG_5V 0x23 -#define LM87_REG_12V 0x24 -#define LM87_REG_VCCP2 0x25 -#define LM87_REG_EXT_TEMP_1 0x26 -#define LM87_REG_INT_TEMP 0x27 /* LM87 temp. */ -#define LM87_REG_FAN1_AIN1 0x28 -#define LM87_REG_FAN2_AIN2 0x29 - -/* These are read/write */ -#define LM87_REG_AIN1_LOW 0x1A -#define LM87_REG_AIN2_LOW 0x1B -#define LM87_REG_2_5V_EXT_TEMP_2_HIGH 0x2B -#define LM87_REG_2_5V_EXT_TEMP_2_LOW 0x2C -#define LM87_REG_VCCP1_HIGH 0x2D -#define LM87_REG_VCCP1_LOW 0x2E -#define LM87_REG_3_3V_HIGH 0x2F -#define LM87_REG_3_3V_LOW 0x30 -#define LM87_REG_5V_HIGH 0x31 -#define LM87_REG_5V_LOW 0x32 -#define LM87_REG_12V_HIGH 0x33 -#define LM87_REG_12V_LOW 0x34 -#define LM87_REG_VCCP2_HIGH 0x35 -#define LM87_REG_VCCP2_LOW 0x36 -#define LM87_REG_EXT_TEMP_1_HIGH 0x37 -#define LM87_REG_EXT_TEMP_1_LOW 0x38 -#define LM87_REG_INT_TEMP_HIGH 0x39 -#define LM87_REG_INT_TEMP_LOW 0x3A -#define LM87_REG_FAN1_AIN1_LIMIT 0x3B -#define LM87_REG_FAN2_AIN2_LIMIT 0x3C -#define LM87_REG_COMPANY_ID 0x3E -#define LM87_REG_DIE_REV 0x3F - -#define LM87_REG_CONFIG 0x40 -#define LM87_REG_INT1_STAT 0x41 -#define LM87_REG_INT2_STAT 0x42 -#define LM87_REG_INT1_MASK 0x43 -#define LM87_REG_INT2_MASK 0x44 -#define LM87_REG_CHASSIS_CLEAR 0x46 -#define LM87_REG_VID_FAN_DIV 0x47 -#define LM87_REG_VID4 0x49 -#define LM87_REG_CONFIG_2 0x4A -#define LM87_REG_INTRPT_STATUS_1_MIRROR 0x4C -#define LM87_REG_INTRPT_STATUS_2_MIRROR 0x4D -#define LM87_REG_SMBALERT_NUM_ENABLE 0x80 - - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:\ - (val)==255?0:1350000/((div)*(val))) - -#define TEMP_FROM_REG(val) ((val)*10) - -#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT(((val)<0?(val)-5:\ - (val)+5)/10,-128,127) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==1?0:((val)==8?3:((val)==4?2:1))) - -/* For each registered LM87, we need to keep some data in memory. The - structure is dynamically allocated whenever a new LM87 client is - found. */ -struct lm87_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[6]; /* Scaled Register value */ - u8 in_max[6]; /* Scaled Register value */ - u8 in_min[6]; /* Scaled Register value */ - u8 ain1; /* Register value */ - u8 ain1_min; /* Register value */ - u8 ain1_max; /* Register value */ - u8 ain2; /* Register value */ - u8 ain2_min; /* Register value */ - u8 ain2_max; /* Register value */ - u8 fan; /* Register value */ - u8 fan_min; /* Register value */ - u8 fan_div; /* Register encoding, shifted right */ - u8 fan2; /* Register value */ - u8 fan2_min; /* Register value */ - u8 fan2_div; /* Register encoding, shifted right */ - s8 ext2_temp; /* Register value */ - s8 ext_temp; /* Register value */ - s8 int_temp; /* Register value */ - u8 ext_temp_max; /* Register value */ - u8 ext_temp_min; /* Register value */ - u8 ext2_temp_max; /* Register value */ - u8 ext2_temp_min; /* Register value */ - u8 int_temp_max; /* Register value */ - u8 int_temp_min; /* Register value */ - u16 alarms; /* Register encoding, combined */ - u8 analog_out; /* Register value */ - u8 vid; /* Register value combined */ - u8 vrm; /* VRM version * 10 */ -}; - -static int lm87_attach_adapter(struct i2c_adapter *adapter); -static int lm87_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int lm87_detach_client(struct i2c_client *client); - -static int lm87_read_value(struct i2c_client *client, u8 register); -static int lm87_write_value(struct i2c_client *client, u8 register, - u8 value); -static void lm87_update_client(struct i2c_client *client); -static void lm87_init_client(struct i2c_client *client); - - -static void lm87_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -#if defined (LM87_AIN1) || defined (LM87_AIN2) -static void lm87_ain(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -#endif -static void lm87_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm87_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm87_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm87_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm87_analog_out(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, - long *results); -static void lm87_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm87_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver LM87_driver = { - .name = "LM87 sensor driver", - .id = I2C_DRIVERID_LM87, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm87_attach_adapter, - .detach_client = lm87_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define LM87_SYSCTL_IN0 1000 /* Volts * 100 */ -#define LM87_SYSCTL_IN1 1001 -#define LM87_SYSCTL_IN2 1002 -#define LM87_SYSCTL_IN3 1003 -#define LM87_SYSCTL_IN4 1004 -#define LM87_SYSCTL_IN5 1005 -#define LM87_SYSCTL_AIN1 1006 -#define LM87_SYSCTL_AIN2 1007 -#define LM87_SYSCTL_FAN1 1102 -#define LM87_SYSCTL_FAN2 1103 -#define LM87_SYSCTL_TEMP1 1250 /* Degrees Celsius * 10 */ -#define LM87_SYSCTL_TEMP2 1251 /* Degrees Celsius * 10 */ -#define LM87_SYSCTL_TEMP3 1252 /* Degrees Celsius * 10 */ -#define LM87_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define LM87_SYSCTL_ALARMS 2001 /* bitvector */ -#define LM87_SYSCTL_ANALOG_OUT 2002 -#define LM87_SYSCTL_VID 2003 -#define LM87_SYSCTL_VRM 2004 - -#define LM87_ALARM_IN0 0x0001 -#define LM87_ALARM_IN1 0x0002 -#define LM87_ALARM_IN2 0x0004 -#define LM87_ALARM_IN3 0x0008 -#define LM87_ALARM_TEMP1 0x0010 -#define LM87_ALARM_TEMP2 0x0020 -#define LM87_ALARM_TEMP3 0x0020 /* same?? */ -#define LM87_ALARM_FAN1 0x0040 -#define LM87_ALARM_FAN2 0x0080 -#define LM87_ALARM_IN4 0x0100 -#define LM87_ALARM_IN5 0x0200 -#define LM87_ALARM_RESERVED1 0x0400 -#define LM87_ALARM_RESERVED2 0x0800 -#define LM87_ALARM_CHAS 0x1000 -#define LM87_ALARM_THERM_SIG 0x2000 -#define LM87_ALARM_TEMP2_FAULT 0x4000 -#define LM87_ALARM_TEMP3_FAULT 0x08000 - -/* -- SENSORS SYSCTL END -- */ - -/* The /proc/sys entries */ -/* These files are created for each detected LM87. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ - -static ctl_table LM87_dir_table_template[] = { -#ifdef LM87_AIN1 - {LM87_SYSCTL_AIN1, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_ain}, -#endif -#ifdef LM87_AIN2 - {LM87_SYSCTL_AIN2, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_ain}, -#endif -#ifndef LM87_EXT2 - {LM87_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_in}, - {LM87_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_in}, -#endif - {LM87_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_in}, - {LM87_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_in}, - {LM87_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_in}, - {LM87_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_in}, -#ifndef LM87_AIN1 - {LM87_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_fan}, - {LM87_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_fan_div}, -#define LM87_FANDIV_FLAG -#endif -#ifndef LM87_AIN2 - {LM87_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_fan}, -#ifndef LM87_FANDIV_FLAG - {LM87_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_fan_div}, -#endif /* LM87_FANDIV_FLAG */ -#endif /* LM87_AIN2 */ -#ifdef LM87_EXT2 - {LM87_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_temp}, -#endif - {LM87_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_temp}, - {LM87_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_temp}, - {LM87_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_alarms}, - {LM87_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_analog_out}, - {LM87_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_vid}, - {LM87_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm87_vrm}, - {0} -}; - -static int lm87_attach_adapter(struct i2c_adapter *adapter) -{ - int error; - struct i2c_client_address_data lm87_client_data; - - lm87_client_data.normal_i2c = addr_data.normal_i2c; - lm87_client_data.normal_i2c_range = addr_data.normal_i2c_range; - lm87_client_data.probe = addr_data.probe; - lm87_client_data.probe_range = addr_data.probe_range; - lm87_client_data.ignore = addr_data.ignore; - lm87_client_data.ignore_range = addr_data.ignore_range; - lm87_client_data.force = addr_data.forces->force; - - error = i2c_probe(adapter, &lm87_client_data, lm87_detect); - i2c_detect(adapter, &addr_data, lm87_detect); - - return error; -} - -static int lm87_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct lm87_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access LM87_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct lm87_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &LM87_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if (((lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80) - != 0x00) || - (lm87_read_value(new_client, LM87_REG_COMPANY_ID) != 0x02)) - goto ERROR1; - } - - /* Fill in the remaining client fields and put into the global list */ - type_name = "lm87"; - client_name = "LM87 chip"; - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - LM87_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the LM87 chip */ - lm87_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int lm87_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct lm87_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR "lm87.o: Client deregistration failed, " - "client not detached\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -#define MAX_RETRIES 5 - -static int lm87_read_value(struct i2c_client *client, u8 reg) -{ - int value, i; - - /* Retry in case of read errors */ - for (i = 1; i <= MAX_RETRIES; i++) { - if ((value = i2c_smbus_read_byte_data(client, reg)) >= 0) - return value; - - printk(KERN_WARNING "lm87.o: Read byte data failed, " - "address 0x%02x\n", reg); - mdelay(i + 3); - } - - /* what to return in case of error? */ - printk(KERN_ERR "lm87.o: All read byte retries failed!!\n"); - return 0; -} - -static int lm87_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new LM87. */ -static void lm87_init_client(struct i2c_client *client) -{ - struct lm87_data *data = client->data; - u8 reg; - - /* Setup Channel Mode register for configuration of monitoring - * Default is 00000000b - * bit 0 - Configures Fan 1/AIN 1 input (1 = AIN) - * bit 1 - Configures Fan 2/AIN 2 input (1 = AIN) - * bit 2 - Configures 2.5V&Vccp2/D2 input (1 = 2nd Therm.) - * bit 3 - Configures Vcc for 5V/3.3V reading (0 = 3.3V) - * bit 4 - Configures IRQ0 Enable if = 1 - * bit 5 - Configures IRQ1 Enable if = 1 - * bit 6 - Configures IRQ2 Enable if = 1 - * bit 7 - Configures VID/IRQ input as interrupts if = 1 - */ - - /* Preserve 4 MSB */ - reg = lm87_read_value(client, LM87_REG_CHANNEL_MODE); -/* I know, not clean, but it works. :'p */ - lm87_write_value(client, LM87_REG_CHANNEL_MODE, (reg & 0xf0) | -#ifdef LM87_AIN1 - 0x01 -#else -0 -#endif - | -#ifdef LM87_AIN2 - 0x02 -#else -0 -#endif - | -#ifdef LM87_EXT2 - 0x04 -#else -0 -#endif - | -#ifdef LM87_5V_VCC -0x08 -#else -0 -#endif - ); - - data->vrm = 82; - - /* Start monitoring */ - reg = lm87_read_value(client, LM87_REG_CONFIG); - if (!(reg & 0x01)) { - printk(KERN_INFO "lm87.o: Monitoring starts\n"); - lm87_write_value(client, LM87_REG_CONFIG, - (reg & 0x7e) | 0x01); - } -} - -static void lm87_update_client(struct i2c_client *client) -{ - struct lm87_data *data = client->data; - int i; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ) || /* 1 sec cache */ - (jiffies < data->last_updated) || - !data->valid) { - for (i = 0; i <= 5; i++) { - data->in[i] = - lm87_read_value(client,LM87_REG_IN(i)); - data->in_min[i] = - lm87_read_value(client,LM87_REG_IN_MIN(i)); - data->in_max[i] = - lm87_read_value(client,LM87_REG_IN_MAX(i)); - } - data->ain1 = - lm87_read_value(client,LM87_REG_FAN1_AIN1); - data->ain1_min = - lm87_read_value(client,LM87_REG_AIN1_LOW); - data->ain1_max = - lm87_read_value(client,LM87_REG_FAN1_AIN1_LIMIT); - data->ain2 = - lm87_read_value(client,LM87_REG_FAN2_AIN2); - data->ain2_min = - lm87_read_value(client,LM87_REG_AIN2_LOW); - data->ain2_max = - lm87_read_value(client,LM87_REG_FAN2_AIN2_LIMIT); - - data->fan = - lm87_read_value(client, LM87_REG_FAN1_AIN1); - data->fan_min = - lm87_read_value(client, LM87_REG_FAN1_AIN1_LIMIT); - data->fan2 = - lm87_read_value(client, LM87_REG_FAN2_AIN2); - data->fan2_min = - lm87_read_value(client, LM87_REG_FAN2_AIN2_LIMIT); - - data->ext2_temp = - lm87_read_value(client, LM87_REG_2_5V_EXT_TEMP_2); - data->ext_temp = - lm87_read_value(client, LM87_REG_EXT_TEMP_1); - data->int_temp = - lm87_read_value(client, LM87_REG_INT_TEMP); - - data->ext2_temp_max = - lm87_read_value(client, LM87_REG_2_5V_EXT_TEMP_2_HIGH); - data->ext2_temp_min = - lm87_read_value(client, LM87_REG_2_5V_EXT_TEMP_2_LOW); - - data->ext_temp_max = - lm87_read_value(client, LM87_REG_EXT_TEMP_1_HIGH); - data->ext_temp_min = - lm87_read_value(client, LM87_REG_EXT_TEMP_1_LOW); - - data->int_temp_max = - lm87_read_value(client, LM87_REG_INT_TEMP_HIGH); - data->int_temp_min = - lm87_read_value(client, LM87_REG_INT_TEMP_LOW); - - i = lm87_read_value(client, LM87_REG_VID_FAN_DIV); - data->fan_div = (i >> 4) & 0x03; - data->fan2_div = (i >> 6) & 0x03; - data->vid = i & 0x0f; - data->vid |= - (lm87_read_value(client, LM87_REG_VID4) & 0x01) - << 4; - data->alarms = - lm87_read_value(client, LM87_REG_INT1_STAT) + - (lm87_read_value(client, LM87_REG_INT2_STAT) << 8); - data->analog_out = - lm87_read_value(client, LM87_REG_ANALOG_OUT); - data->last_updated = jiffies; - data->valid = 1; - } - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void lm87_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - long scales[6] = { 250, 270, -#ifdef LM87_5V_VCC -500, -#else -330, -#endif - 500, 1200, 270 }; - - struct lm87_data *data = client->data; - int nr = ctl_name - LM87_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm87_update_client(client); - results[0] = (data->in_min[nr] * scales[nr] + 96) / 192; - results[1] = (data->in_max[nr] * scales[nr] + 96) / 192; - results[2] = (data->in[nr] * scales[nr] + 96) / 192; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = (results[0] * 192 + scales[nr] / 2) - / scales[nr]; - lm87_write_value(client, LM87_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = (results[1] * 192 + scales[nr] / 2) - / scales[nr]; - lm87_write_value(client, LM87_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -#if defined (LM87_AIN1) || defined (LM87_AIN2) -void lm87_ain(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm87_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm87_update_client(client); - if (ctl_name == LM87_SYSCTL_AIN1) { - results[0] = data->ain1_min; - results[1] = data->ain1_max; - results[2] = data->ain1; - } else { - results[0] = data->ain2_min; - results[1] = data->ain2_max; - results[2] = data->ain2; - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (ctl_name == LM87_SYSCTL_AIN1) { - data->ain1_min = results[0]; - lm87_write_value(client, LM87_REG_AIN1_LOW, - data->ain1_min); - } else { - data->ain2_min = results[0]; - lm87_write_value(client, LM87_REG_AIN2_LOW, - data->ain2_min); - } - } - if (*nrels_mag >= 2) { - if (ctl_name == LM87_SYSCTL_AIN1) { - data->ain1_max = results[1]; - lm87_write_value(client, LM87_REG_FAN1_AIN1_LIMIT, - data->ain1_max); - } else { - data->ain2_max = results[1]; - lm87_write_value(client, LM87_REG_FAN2_AIN2_LIMIT, - data->ain2_max); - } - } - } -} -#endif - -void lm87_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm87_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm87_update_client(client); - if (ctl_name == LM87_SYSCTL_FAN1) { - results[0] = FAN_FROM_REG(data->fan_min, - DIV_FROM_REG(data->fan_div)); - results[1] = FAN_FROM_REG(data->fan, - DIV_FROM_REG(data->fan_div)); - } else { - results[0] = FAN_FROM_REG(data->fan2_min, - DIV_FROM_REG(data->fan2_div)); - results[1] = FAN_FROM_REG(data->fan2, - DIV_FROM_REG(data->fan2_div)); - } - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 0) { - if (ctl_name == LM87_SYSCTL_FAN1) { - data->fan_min = FAN_TO_REG(results[0], - DIV_FROM_REG - (data->fan_div)); - lm87_write_value(client, LM87_REG_FAN1_AIN1_LIMIT, - data->fan_min); - } else { - data->fan2_min = FAN_TO_REG(results[0], - DIV_FROM_REG - (data->fan2_div)); - lm87_write_value(client, LM87_REG_FAN2_AIN2_LIMIT, - data->fan2_min); - } - } - } -} - - -void lm87_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm87_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) - { - lm87_update_client(client); - - /* find out which temp. is being requested */ - if (ctl_name == LM87_SYSCTL_TEMP3) - { - results[0] = TEMP_FROM_REG(data->ext2_temp_max); - results[1] = TEMP_FROM_REG(data->ext2_temp_min); - results[2] = TEMP_FROM_REG(data->ext2_temp); - } - else if(ctl_name == LM87_SYSCTL_TEMP2) - { - results[0] = TEMP_FROM_REG(data->ext_temp_max); - results[1] = TEMP_FROM_REG(data->ext_temp_min); - results[2] = TEMP_FROM_REG(data->ext_temp); - } - else if(ctl_name == LM87_SYSCTL_TEMP1) - { - results[0] = TEMP_FROM_REG(data->int_temp_max); - results[1] = TEMP_FROM_REG(data->int_temp_min); - results[2] = TEMP_FROM_REG(data->int_temp); - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (ctl_name == LM87_SYSCTL_TEMP3) { - data->ext2_temp_max = TEMP_LIMIT_TO_REG(results[0]); - lm87_write_value(client, LM87_REG_2_5V_EXT_TEMP_2_HIGH, - data->ext2_temp_max); - } - if (ctl_name == LM87_SYSCTL_TEMP2) { - data->ext_temp_max = TEMP_LIMIT_TO_REG(results[0]); - lm87_write_value(client, LM87_REG_EXT_TEMP_1_HIGH, - data->ext_temp_max); - } - if (ctl_name == LM87_SYSCTL_TEMP1) { - data->int_temp_max = TEMP_LIMIT_TO_REG(results[0]); - lm87_write_value(client, LM87_REG_INT_TEMP_HIGH, - data->int_temp_max); - } - } - if (*nrels_mag >= 2) { - if (ctl_name == LM87_SYSCTL_TEMP3) { - data->ext2_temp_min = TEMP_LIMIT_TO_REG(results[1]); - lm87_write_value(client, LM87_REG_2_5V_EXT_TEMP_2_LOW, - data->ext2_temp_min); - } - if (ctl_name == LM87_SYSCTL_TEMP2) { - data->ext_temp_min = TEMP_LIMIT_TO_REG(results[1]); - lm87_write_value(client, LM87_REG_EXT_TEMP_1_LOW, - data->ext_temp_min); - } - if (ctl_name == LM87_SYSCTL_TEMP1) { - data->int_temp_min = TEMP_LIMIT_TO_REG(results[1]); - lm87_write_value(client, LM87_REG_INT_TEMP_LOW, - data->int_temp_min); - } - } - } -} - -void lm87_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm87_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm87_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -void lm87_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ -/* This gets a little hairy depending on the hardware config */ - - struct lm87_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm87_update_client(client); -#ifndef LM87_AIN1 - results[0] = DIV_FROM_REG(data->fan_div); -# ifndef LM87_AIN2 - results[1] = DIV_FROM_REG(data->fan2_div); - *nrels_mag = 2; -# else - *nrels_mag = 1; -# endif -#else /* Must be referring to fan 2 */ - results[0] = DIV_FROM_REG(data->fan2_div); - *nrels_mag = 1; -#endif - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = lm87_read_value(client, LM87_REG_VID_FAN_DIV); -/* Note: it's OK to change fan2 div even if fan2 isn't enabled */ -#ifndef LM87_AIN1 - if (*nrels_mag >= 2) { - data->fan2_div = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan2_div << 6); - } - if (*nrels_mag >= 1) { - data->fan_div = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div << 4); - lm87_write_value(client, LM87_REG_VID_FAN_DIV, old); - } -#else /* Must be referring to fan 2 */ - if (*nrels_mag >= 1) { - data->fan2_div = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan2_div << 6); - lm87_write_value(client, LM87_REG_VID_FAN_DIV, old); - } -#endif - } -} - -void lm87_analog_out(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm87_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm87_update_client(client); - results[0] = data->analog_out; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->analog_out = results[0]; - lm87_write_value(client, LM87_REG_ANALOG_OUT, - data->analog_out); - } - } -} - -void lm87_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm87_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - lm87_update_client(client); - results[0] = vid_from_reg(data->vid, data->vrm); - *nrels_mag = 1; - } -} - -void lm87_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm87_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) - data->vrm = results[0]; - } -} - -static int __init sm_lm87_init(void) -{ - printk(KERN_INFO "lm87.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&LM87_driver); -} - -static void __exit sm_lm87_exit(void) -{ - i2c_del_driver(&LM87_driver); -} - - - -MODULE_LICENSE("GPL"); - -MODULE_AUTHOR - ("Frodo Looijaard , Philip Edelbrock , " - "Mark Studebaker , and Stephen Rousset "); - -MODULE_DESCRIPTION("LM87 driver"); - -module_init(sm_lm87_init); -module_exit(sm_lm87_exit); diff --git a/kernel/chips/lm90.c b/kernel/chips/lm90.c deleted file mode 100644 index 9e5e38d1..00000000 --- a/kernel/chips/lm90.c +++ /dev/null @@ -1,858 +0,0 @@ -/* - * lm90.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2003-2005 Jean Delvare - * - * Based on the lm83 driver. The LM90 is a sensor chip made by National - * Semiconductor. It reports up to two temperatures (its own plus up to - * one external one) with a 0.125 deg resolution (1 deg for local - * temperature) and a 3-4 deg accuracy. Complete datasheet can be - * obtained from National's website at: - * http://www.national.com/pf/LM/LM90.html - * - * This driver also supports the LM89 and LM99, two other sensor chips - * made by National Semiconductor. Both have an increased remote - * temperature measurement accuracy (1 degree), and the LM99 - * additionally shifts remote temperatures (measured and limits) by 16 - * degrees, which allows for higher temperatures measurement. The - * driver doesn't handle it since it can be done easily in user-space. - * Complete datasheets can be obtained from National's website at: - * http://www.national.com/pf/LM/LM89.html - * http://www.national.com/pf/LM/LM99.html - * Note that there is no way to differentiate between both chips. - * - * This driver also supports the LM86, another sensor chip made by - * National Semiconductor. It is exactly similar to the LM90 except it - * has a higher accuracy. - * Complete datasheet can be obtained from National's website at: - * http://www.national.com/pf/LM/LM86.html - * - * This driver also supports the ADM1032, a sensor chip made by Analog - * Devices. That chip is similar to the LM90, with a few differences - * that are not handled by this driver. Complete datasheet can be - * obtained from Analog's website at: - * http://products.analog.com/products/info.asp?product=ADM1032 - * Among others, it has a higher accuracy than the LM90, much like the - * LM86 does. - * - * This driver also supports the MAX6657, MAX6658 and MAX6659 sensor - * chips made by Maxim. These chips are similar to the LM86. Complete - * datasheet can be obtained at Maxim's website at: - * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 - * Note that there is no easy way to differentiate between the three - * variants. The extra address and features of the MAX6659 are not - * supported by this driver. - * - * This driver also supports the ADT7461 chip from Analog Devices but - * only in its "compatability mode". If an ADT7461 chip is found but - * is configured in non-compatible mode (where its temperature - * register values are decoded differently) it is ignored by this - * driver. Complete datasheet can be obtained from Analog's website - * at: - * http://products.analog.com/products/info.asp?product=ADT7461 - * - * Since the LM90 was the first chipset supported by this driver, most - * comments will refer to this chipset, but are actually general and - * concern all supported chipsets, unless mentioned otherwise. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include "version.h" - -#ifndef I2C_DRIVERID_LM90 -#define I2C_DRIVERID_LM90 1042 -#endif - -/* - * Addresses to scan - * Address is fully defined internally and cannot be changed except for - * MAX6659. - * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6657 and MAX6658 - * have address 0x4c. - * ADM1032-2, ADT7461-2, LM89-1, and LM99-1 have address 0x4d. - * MAX6659 can have address 0x4c, 0x4d or 0x4e (unsupported). - */ - -static unsigned short normal_i2c[] = { 0x4c, 0x4d, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461); - -/* - * The LM90 registers - */ - -#define LM90_REG_R_MAN_ID 0xFE -#define LM90_REG_R_CHIP_ID 0xFF -#define LM90_REG_R_CONFIG1 0x03 -#define LM90_REG_W_CONFIG1 0x09 -#define LM90_REG_R_CONFIG2 0xBF -#define LM90_REG_W_CONFIG2 0xBF -#define LM90_REG_R_CONVRATE 0x04 -#define LM90_REG_W_CONVRATE 0x0A -#define LM90_REG_R_STATUS 0x02 -#define LM90_REG_R_LOCAL_TEMP 0x00 -#define LM90_REG_R_LOCAL_HIGH 0x05 -#define LM90_REG_W_LOCAL_HIGH 0x0B -#define LM90_REG_R_LOCAL_LOW 0x06 -#define LM90_REG_W_LOCAL_LOW 0x0C -#define LM90_REG_R_LOCAL_CRIT 0x20 -#define LM90_REG_W_LOCAL_CRIT 0x20 -#define LM90_REG_R_REMOTE_TEMPH 0x01 -#define LM90_REG_R_REMOTE_TEMPL 0x10 -#define LM90_REG_R_REMOTE_OFFSH 0x11 -#define LM90_REG_W_REMOTE_OFFSH 0x11 -#define LM90_REG_R_REMOTE_OFFSL 0x12 -#define LM90_REG_W_REMOTE_OFFSL 0x12 -#define LM90_REG_R_REMOTE_HIGHH 0x07 -#define LM90_REG_W_REMOTE_HIGHH 0x0D -#define LM90_REG_R_REMOTE_HIGHL 0x13 -#define LM90_REG_W_REMOTE_HIGHL 0x13 -#define LM90_REG_R_REMOTE_LOWH 0x08 -#define LM90_REG_W_REMOTE_LOWH 0x0E -#define LM90_REG_R_REMOTE_LOWL 0x14 -#define LM90_REG_W_REMOTE_LOWL 0x14 -#define LM90_REG_R_REMOTE_CRIT 0x19 -#define LM90_REG_W_REMOTE_CRIT 0x19 -#define LM90_REG_R_TCRIT_HYST 0x21 -#define LM90_REG_W_TCRIT_HYST 0x21 - -/* - * Conversions and various macros - * For local temperatures and limits, critical limits and the hysteresis - * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius. - * For remote temperatures and limits, it uses signed 11-bit values with - * LSB = 0.125 degree Celsius, left-justified in 16-bit registers. - */ - -#define TEMP1_FROM_REG(val) (val) -#define TEMP1_TO_REG(val) ((val) <= -128 ? -128 : \ - (val) >= 127 ? 127 : (val)) -#define TEMP2_FROM_REG(val) ((val) / 32 * 125 / 100) -#define TEMP2_TO_REG(val) ((val) <= -1280 ? 0x8000 : \ - (val) >= 1270 ? 0x7FE0 : \ - ((val) * 100 / 125 * 32)) -#define HYST_TO_REG(val) ((val) <= 0 ? 0 : \ - (val) >= 31 ? 31 : (val)) - -/* - * ADT7461 is almost identical to LM90 except that attempts to write - * values that are outside the range 0 < temp < 127 are treated as - * the boundary value. - */ - -#define TEMP1_TO_REG_ADT7461(val) ((val) <= 0 ? 0 : \ - (val) >= 127 ? 127 : (val)) -#define TEMP2_TO_REG_ADT7461(val) ((val) <= 0 ? 0 : \ - (val) >= 1277 ? 0x7FC0 : \ - ((val) * 100 / 250 * 64)) - -/* - * Functions declaration - */ - -static int lm90_attach_adapter(struct i2c_adapter *adapter); -static int lm90_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void lm90_init_client(struct i2c_client *client); -static int lm90_detach_client(struct i2c_client *client); -static void lm90_local_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm90_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm90_local_tcrit(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm90_remote_tcrit(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm90_local_hyst(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm90_remote_hyst(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm90_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1032_pec(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver lm90_driver = { - .name = "LM90/ADM1032 sensor driver", - .id = I2C_DRIVERID_LM90, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm90_attach_adapter, - .detach_client = lm90_detach_client -}; - -/* - * Client data (each client gets its own) - */ - -struct lm90_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - int kind; - - /* registers values */ - s8 local_temp, local_high, local_low; - s16 remote_temp, remote_high, remote_low; /* combined */ - s8 local_crit, remote_crit; - u8 hyst; /* linked to two sysctl files (hyst1 RW, hyst2 RO) */ - u8 alarms; /* bitvector */ -}; - -/* - * Proc entries - * These files are created for each detected LM90. - */ - -/* -- SENSORS SYSCTL START -- */ - -#define LM90_SYSCTL_LOCAL_TEMP 1200 -#define LM90_SYSCTL_REMOTE_TEMP 1201 -#define LM90_SYSCTL_LOCAL_TCRIT 1204 -#define LM90_SYSCTL_REMOTE_TCRIT 1205 -#define LM90_SYSCTL_LOCAL_HYST 1207 -#define LM90_SYSCTL_REMOTE_HYST 1208 -#define LM90_SYSCTL_ALARMS 1210 -#define LM90_SYSCTL_PEC 1214 - -#define LM90_ALARM_LOCAL_HIGH 0x40 -#define LM90_ALARM_LOCAL_LOW 0x20 -#define LM90_ALARM_LOCAL_CRIT 0x01 -#define LM90_ALARM_REMOTE_HIGH 0x10 -#define LM90_ALARM_REMOTE_LOW 0x08 -#define LM90_ALARM_REMOTE_CRIT 0x02 -#define LM90_ALARM_REMOTE_OPEN 0x04 - -/* -- SENSORS SYSCTL END -- */ - - -static ctl_table lm90_dir_table_template[] = -{ - {LM90_SYSCTL_LOCAL_TEMP, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_local_temp}, - {LM90_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_remote_temp}, - {LM90_SYSCTL_LOCAL_TCRIT, "tcrit1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_local_tcrit}, - {LM90_SYSCTL_REMOTE_TCRIT, "tcrit2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_remote_tcrit}, - {LM90_SYSCTL_LOCAL_HYST, "hyst1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_local_hyst}, - {LM90_SYSCTL_REMOTE_HYST, "hyst2", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_remote_hyst}, - {LM90_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_alarms}, - {0} -}; - -static ctl_table adm1032_dir_table_template[] = -{ - {LM90_SYSCTL_LOCAL_TEMP, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_local_temp}, - {LM90_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_remote_temp}, - {LM90_SYSCTL_LOCAL_TCRIT, "tcrit1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_local_tcrit}, - {LM90_SYSCTL_REMOTE_TCRIT, "tcrit2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_remote_tcrit}, - {LM90_SYSCTL_LOCAL_HYST, "hyst1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_local_hyst}, - {LM90_SYSCTL_REMOTE_HYST, "hyst2", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_remote_hyst}, - {LM90_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm90_alarms}, - {LM90_SYSCTL_PEC, "pec", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &adm1032_pec}, - {0} -}; - -/* - * Real code - */ - -/* The ADM1032 supports PEC but not on write byte transactions, so we need - to explicitly ask for a transaction without PEC. */ -static inline s32 adm1032_write_byte(struct i2c_client *client, u8 value) -{ - return i2c_smbus_xfer(client->adapter, client->addr, - client->flags & ~I2C_CLIENT_PEC, - I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); -} - -/* It is assumed that client->update_lock is held (unless we are in - detection or initialization steps). This matters when PEC is enabled, - because we don't want the address pointer to change between the write - byte and the read byte transactions. */ -static int lm90_read_reg(struct i2c_client* client, u8 reg, u8 *value) -{ - int err; - - if (client->flags & I2C_CLIENT_PEC) { - err = adm1032_write_byte(client, reg); - if (err >= 0) - err = i2c_smbus_read_byte(client); - } else - err = i2c_smbus_read_byte_data(client, reg); - - if (err < 0) { - printk(KERN_WARNING "lm90: Register 0x%02x read failed (%d)\n", - reg, err); - return err; - } - *value = err; - - return 0; -} - -static int lm90_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, lm90_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int lm90_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - struct i2c_client *new_client; - struct lm90_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { -#ifdef DEBUG - printk(KERN_DEBUG "lm90: adapter doesn't support byte mode, " - "skipping\n"); -#endif - return 0; - } - - if (!(data = kmalloc(sizeof(struct lm90_data), GFP_KERNEL))) { - printk(KERN_ERR "lm90: Out of memory in lm90_detect\n"); - return -ENOMEM; - } - - /* - * The common I2C client data is placed right before the - * LM90-specific data. The LM90-specific data is pointed to by the - * data field from the I2C client data. - */ - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &lm90_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip. A zero kind means that - * the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - */ - - /* Default to an LM90 if forced */ - if (kind == 0) - kind = lm90; - - if (kind < 0) { /* detection and identification */ - u8 man_id, chip_id, reg_config1, reg_convrate; - - if (lm90_read_reg(new_client, LM90_REG_R_MAN_ID, - &man_id) < 0 - || lm90_read_reg(new_client, LM90_REG_R_CHIP_ID, - &chip_id) < 0 - || lm90_read_reg(new_client, LM90_REG_R_CONFIG1, - ®_config1) < 0 - || lm90_read_reg(new_client, LM90_REG_R_CONVRATE, - ®_convrate) < 0) - goto exit_free; - - if (man_id == 0x01) { /* National Semiconductor */ - u8 reg_config2; - - if (lm90_read_reg(new_client, LM90_REG_R_CONFIG2, - ®_config2) < 0) - goto exit_free; - - if ((reg_config1 & 0x2A) == 0x00 - && (reg_config2 & 0xF8) == 0x00 - && reg_convrate <= 0x09) { - if (address == 0x4C - && (chip_id & 0xF0) == 0x20) /* LM90 */ - kind = lm90; - else if ((chip_id & 0xF0) == 0x30) /* LM89/LM99 */ - kind = lm99; - else if (address == 0x4C - && (chip_id & 0xF0) == 0x10) /* LM86 */ - kind = lm99; - } - } else - if (man_id == 0x41) { /* Analog Devices */ - if ((chip_id & 0xF0) == 0x40 /* ADM1032 */ - && (reg_config1 & 0x3F) == 0x00 - && reg_convrate <= 0x0A) - kind = adm1032; - else - if (chip_id == 0x51 /* ADT7461 */ - && (reg_config1 & 0x1F) == 0x00 /* check compat mode */ - && reg_convrate <= 0x0A) - kind = adt7461; - } else - if (man_id == 0x4D) { /* Maxim */ - /* - * The Maxim variants do NOT have a chip_id register. - * Reading from that address will return the last read - * value, which in our case is those of the man_id - * register. Likewise, the config1 register seems to - * lack a low nibble, so the value will be those of the - * previous read, so in our case those of the man_id - * register. - */ - if (chip_id == man_id - && (reg_config1 & 0x1F) == (man_id & 0x0F) - && reg_convrate <= 0x09) - kind = max6657; - } - } - - if (kind <= 0) { /* identification failed */ - printk(KERN_INFO "lm90: Unsupported chip\n"); - goto exit_free; - } - - if (kind == lm90) { - type_name = "lm90"; - client_name = "LM90 chip"; - } else if (kind == adm1032) { - type_name = "adm1032"; - client_name = "ADM1032 chip"; - /* The ADM1032 supports PEC, but only if combined - transactions are not used. */ - if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) { - new_client->flags |= I2C_CLIENT_PEC; - printk(KERN_DEBUG "lm90: Enabling PEC for ADM1032\n"); - } - } else if (kind == lm99) { - type_name = "lm99"; - client_name = "LM99 chip"; - } else if (kind == lm86) { - type_name = "lm86"; - client_name = "LM86 chip"; - } else if (kind == max6657) { - type_name = "max6657"; - client_name = "MAX6657 chip"; - } else if (kind == adt7461) { - type_name = "adt7461"; - client_name = "ADT7561 chip"; - } else { - printk(KERN_ERR "lm90: Unknown kind %d\n", kind); - goto exit_free; - } - - /* - * OK, we got a valid chip so we can fill in the remaining client - * fields. - */ - - strcpy(new_client->name, client_name); - data->valid = 0; - data->kind = kind; - init_MUTEX(&data->update_lock); - - /* - * Tell the I2C layer a new client has arrived. - */ - - if ((err = i2c_attach_client(new_client))) { - printk(KERN_ERR "lm90: Failed to attach client (%d)\n", err); - goto exit_free; - } - - /* - * Register a new directory entry. - */ - - if ((err = i2c_register_entry(new_client, type_name, - (new_client->flags & I2C_CLIENT_PEC) ? - adm1032_dir_table_template : - lm90_dir_table_template, THIS_MODULE)) < 0) { - printk(KERN_ERR "lm90: Failed to register directory entry " - "(%d)\n", err); - goto exit_detach; - } - data->sysctl_id = err; - - /* - * Initialize the LM90 chip. - */ - - lm90_init_client(new_client); - return 0; - -exit_detach: - i2c_detach_client(new_client); -exit_free: - kfree(data); - return err; -} - -static void lm90_init_client(struct i2c_client *client) -{ - u8 config; - - /* - * Start the conversions. - */ - - i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, - 5); /* 2 Hz */ - if (lm90_read_reg(client, LM90_REG_R_CONFIG1, &config) < 0) { - printk(KERN_ERR "lm90: Initialization failed!\n"); - return; - } - if (config & 0x40) - i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, - config & 0xBF); /* run */ -} - - -static int lm90_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct lm90_data *) (client->data))->sysctl_id); - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR "lm90: Client deregistration failed, client " - "not detached (%d)\n", err); - return err; - } - - kfree(client->data); - return 0; -} - -static void lm90_update_client(struct i2c_client *client) -{ - struct lm90_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ * 2) || - (jiffies < data->last_updated) || !data->valid) { - u8 oldh, newh, l; -#ifdef DEBUG - printk(KERN_DEBUG "lm90: Updating register values\n"); -#endif - - lm90_read_reg(client, LM90_REG_R_LOCAL_TEMP, - &data->local_temp); - lm90_read_reg(client, LM90_REG_R_LOCAL_HIGH, - &data->local_high); - lm90_read_reg(client, LM90_REG_R_LOCAL_LOW, - &data->local_low); - lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT, - &data->local_crit); - lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT, - &data->remote_crit); - lm90_read_reg(client, LM90_REG_R_TCRIT_HYST, - &data->hyst); - - /* - * There is a trick here. We have to read two registers to - * have the remote sensor temperature, but we have to beware - * a conversion could occur inbetween the readings. The - * datasheet says we should either use the one-shot - * conversion register, which we don't want to do (disables - * hardware monitoring) or monitor the busy bit, which is - * impossible (we can't read the values and monitor that bit - * at the exact same time). So the solution used here is to - * read the high byte once, then the low byte, then the high - * byte again. If the new high byte matches the old one, - * then we have a valid reading. Else we have to read the low - * byte again, and now we believe we have a correct reading. - */ - - if (lm90_read_reg(client, LM90_REG_R_REMOTE_TEMPH, &oldh) == 0 - && lm90_read_reg(client, LM90_REG_R_REMOTE_TEMPL, &l) == 0 - && lm90_read_reg(client, LM90_REG_R_REMOTE_TEMPH, &newh) == 0 - && (newh == oldh - || lm90_read_reg(client, LM90_REG_R_REMOTE_TEMPL, &l) == 0)) - data->remote_temp = (newh << 8) | l; - - if (lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH, &newh) == 0 - && lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL, &l) == 0) - data->remote_low = (newh << 8) | l; - if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &newh) == 0 - && lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL, &l) == 0) - data->remote_high = (newh << 8) | l; - lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -static void lm90_local_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm90_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm90_update_client(client); - results[0] = TEMP1_FROM_REG(data->local_high); - results[1] = TEMP1_FROM_REG(data->local_low); - results[2] = TEMP1_FROM_REG(data->local_temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (data->kind == adt7461) - data->local_high = TEMP1_TO_REG_ADT7461(results[0]); - else - data->local_high = TEMP1_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, LM90_REG_W_LOCAL_HIGH, - data->local_high); - } - if (*nrels_mag >= 2) { - if (data->kind == adt7461) - data->local_low = TEMP1_TO_REG_ADT7461(results[1]); - else - data->local_low = TEMP1_TO_REG(results[1]); - i2c_smbus_write_byte_data(client, LM90_REG_W_LOCAL_LOW, - data->local_low); - } - } -} - -static void lm90_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm90_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm90_update_client(client); - results[0] = TEMP2_FROM_REG(data->remote_high); - results[1] = TEMP2_FROM_REG(data->remote_low); - results[2] = TEMP2_FROM_REG(data->remote_temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (data->kind == adt7461) - data->remote_high = TEMP2_TO_REG_ADT7461(results[0]); - else - data->remote_high = TEMP2_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_HIGHH, - data->remote_high >> 8); - i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_HIGHL, - data->remote_high & 0xFF); - } - if (*nrels_mag >= 2) { - if (data->kind == adt7461) - data->remote_low = TEMP2_TO_REG_ADT7461(results[1]); - else - data->remote_low = TEMP2_TO_REG(results[1]); - i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_LOWH, - data->remote_low >> 8); - i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_LOWL, - data->remote_low & 0xFF); - } - } -} - -static void lm90_local_tcrit(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm90_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm90_update_client(client); - results[0] = TEMP1_FROM_REG(data->local_crit); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (data->kind == adt7461) - data->local_crit = TEMP1_TO_REG_ADT7461(results[0]); - else - data->local_crit = TEMP1_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, LM90_REG_W_LOCAL_CRIT, - data->local_crit); - } - } -} - -static void lm90_remote_tcrit(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm90_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm90_update_client(client); - results[0] = TEMP1_FROM_REG(data->remote_crit); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (data->kind == adt7461) - data->remote_crit = TEMP1_TO_REG_ADT7461(results[0]); - else - data->remote_crit = TEMP1_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_CRIT, - data->remote_crit); - } - } -} - -/* - * One quick note about hysteresis. Internally, the hysteresis value - * is held in a single register by the LM90, as a relative value. - * This relative value applies to both the local critical temperature - * and the remote critical temperature. Since all temperatures exported - * through procfs have to be absolute, we have to do some conversions. - * The solution retained here is to export two absolute values, one for - * each critical temperature. In order not to confuse the users too - * much, only one file is writable. Would we fail to do so, users - * would probably attempt to write to both files, as if they were - * independant, and since they aren't, they wouldn't understand why - * setting one affects the other one (and would probably claim there's - * a bug in the driver). - */ - -static void lm90_local_hyst(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm90_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm90_update_client(client); - results[0] = TEMP1_FROM_REG(data->local_crit) - - TEMP1_FROM_REG(data->hyst); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->hyst = HYST_TO_REG(data->local_crit - results[0]); - i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST, - data->hyst); - } - } -} - -static void lm90_remote_hyst(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm90_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm90_update_client(client); - results[0] = TEMP1_FROM_REG(data->remote_crit) - - TEMP1_FROM_REG(data->hyst); - *nrels_mag = 1; - } -} - -static void lm90_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm90_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - lm90_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -/* pec used for ADM1032 only */ -static void adm1032_pec(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = !!(client->flags & I2C_CLIENT_PEC); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - switch (results[0]) { - case 0: - client->flags &= ~I2C_CLIENT_PEC; - break; - case 1: - client->flags |= I2C_CLIENT_PEC; - break; - } - } - } -} - -static int __init sm_lm90_init(void) -{ - printk(KERN_INFO "lm90 driver version %s (%s)\n", LM_VERSION, - LM_DATE); - return i2c_add_driver(&lm90_driver); -} - -static void __exit sm_lm90_exit(void) -{ - i2c_del_driver(&lm90_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("LM90/ADM1032 sensor driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_lm90_init); -module_exit(sm_lm90_exit); diff --git a/kernel/chips/lm92.c b/kernel/chips/lm92.c deleted file mode 100644 index 73154fcb..00000000 --- a/kernel/chips/lm92.c +++ /dev/null @@ -1,416 +0,0 @@ - -/* - * LM92 - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * - * Author: Abraham van der Merwe - * - * Linux support for the National Semiconductor LM92 Temperature - * Sensor. - * - * Based on code from the lm-sensors project which is available - * at http://www.lm-sensors.org/. lm87.c have been particularly - * helpful (: - * - * This source code is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" - -/* if defined, 4 faults must occur consecutively to set alarm flags */ -/* #define ENABLE_FAULT_QUEUE */ - -#define LM92_REG_TEMPERATURE 0x00 /* ro, 16-bit */ -#define LM92_REG_CONFIGURATION 0x01 /* rw, 8-bit */ -#define LM92_REG_TRIP_HYSTERESIS 0x02 /* rw, 16-bit */ -#define LM92_REG_TRIP_CRITICAL 0x03 /* rw, 16-bit */ -#define LM92_REG_TRIP_LOW 0x04 /* rw, 16-bit */ -#define LM92_REG_TRIP_HIGH 0x05 /* rw, 16-bit */ -#define LM92_REG_MANUFACTURER 0x07 /* ro, 16-bit */ - -#define LM92_MANUFACTURER_ID 0x8001 - -#define TEMP_MIN (-4096) -#define TEMP_MAX 4095 - -#define LIMIT(x) do { \ - if ((x) < TEMP_MIN) (x) = TEMP_MIN; \ - if ((x) > TEMP_MAX) (x) = TEMP_MAX; \ - } while (0) - -#define PROC_TO_NATIVE(x) ((x) / 625) -#define NATIVE_TO_PROC(x) ((x) * 625) -#define CELSIUS(x) ((x) * 16) - -static void lm92_temp (struct i2c_client *client,int operation,int ctl_name,int *nrels_mag,long *results); -static void lm92_alarms (struct i2c_client *client,int operation,int ctl_name,int *nrels_mag,long *results); - -/* -- SENSORS SYSCTL START -- */ -#define LM92_SYSCTL_ALARMS 2001 /* high, low, critical */ -#define LM92_SYSCTL_TEMP 1200 /* high, low, critical, hysteresis, input */ - -#define LM92_ALARM_TEMP_HIGH 0x01 -#define LM92_ALARM_TEMP_LOW 0x02 -#define LM92_ALARM_TEMP_CRIT 0x04 -#define LM92_TEMP_HIGH 0x08 -#define LM92_TEMP_LOW 0x10 -#define LM92_TEMP_CRIT 0x20 -#define LM92_TEMP_HYST 0x40 -#define LM92_TEMP_INPUT 0x80 - -/* -- SENSORS SYSCTL END -- */ - -static ctl_table lm92_dir_table[] = { - {LM92_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm92_temp, NULL}, - {LM92_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm92_alarms, NULL}, - {0} -}; - -/* NOTE: all temperatures are degrees centigrade * 16 */ -typedef struct { - struct i2c_client client; - int sysctl_id; - unsigned long timestamp; - struct { - long high; - long low; - long crit; - long hyst; - long input; - } temp; - struct { - long low; - long high; - long crit; - } alarms; -} lm92_t; - -/* this is needed for each client driver method */ -static struct i2c_driver lm92_driver; - -/* ensure exclusive access to chip and static variables */ -static DECLARE_MUTEX (mutex); - -/* addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x48, 0x4f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* insmod parameters */ -SENSORS_INSMOD_1 (lm92); - -static inline int lm92_write8 (struct i2c_client *client,u8 reg,u8 value) -{ - return (i2c_smbus_write_byte_data (client,reg,value) < 0 ? -EIO : 0); -} - -static inline int lm92_read16 (struct i2c_client *client,u8 reg,u16 *value) -{ - s32 tmp = i2c_smbus_read_word_data (client,reg); - - if (tmp < 0) return (-EIO); - - /* convert the data to little endian format */ - *value = swab16((u16) tmp); - - return (0); -} - -static inline int lm92_write16 (struct i2c_client *client,u8 reg,u16 value) -{ - /* convert the data to big endian format */ - if (i2c_smbus_write_word_data(client, reg, swab16(value)) < 0) - return -EIO; - - return 0; -} - -static int lm92_read (struct i2c_client *client) -{ - lm92_t *data = (lm92_t *) client->data; - u16 value[5]; - - if ((jiffies - data->timestamp) > HZ) { - if (lm92_read16 (client,LM92_REG_TEMPERATURE,value) < 0 || - lm92_read16 (client,LM92_REG_TRIP_HYSTERESIS,value + 1) < 0 || - lm92_read16 (client,LM92_REG_TRIP_CRITICAL,value + 2) < 0 || - lm92_read16 (client,LM92_REG_TRIP_LOW,value + 3) < 0 || - lm92_read16 (client,LM92_REG_TRIP_HIGH,value + 4) < 0) - return (-EIO); - - data->temp.input = (s16) value[0] >> 3; - data->temp.hyst = (s16) value[1] >> 3; - data->temp.crit = (s16) value[2] >> 3; - data->temp.low = (s16) value[3] >> 3; - data->temp.high = (s16) value[4] >> 3; - - data->alarms.low = value[0] & 1; - data->alarms.high = (value[0] & 2) >> 1; - data->alarms.crit = (value[0] & 4) >> 2; - - data->timestamp = jiffies; - } - - return (0); -} - -static int lm92_write (struct i2c_client *client) -{ - lm92_t *data = (lm92_t *) client->data; - - LIMIT (data->temp.hyst); - LIMIT (data->temp.crit); - LIMIT (data->temp.low); - LIMIT (data->temp.high); - - if (lm92_write16 (client,LM92_REG_TRIP_HYSTERESIS,((s16) data->temp.hyst << 3)) < 0 || - lm92_write16 (client,LM92_REG_TRIP_CRITICAL,((s16) data->temp.crit << 3)) < 0 || - lm92_write16 (client,LM92_REG_TRIP_LOW,((s16) data->temp.low << 3)) < 0 || - lm92_write16 (client,LM92_REG_TRIP_HIGH,((s16) data->temp.high << 3)) < 0) - return (-EIO); - - return (0); -} - -static void lm92_temp (struct i2c_client *client,int operation,int ctl_name,int *nrels_mag,long *results) -{ - if (!down_interruptible (&mutex)) { - lm92_t *data = (lm92_t *) client->data; - - if (operation == SENSORS_PROC_REAL_READ) { - lm92_read (client); - results[0] = NATIVE_TO_PROC (data->temp.input); - results[1] = NATIVE_TO_PROC (data->temp.high); - results[2] = NATIVE_TO_PROC (data->temp.low); - results[3] = NATIVE_TO_PROC (data->temp.crit); - results[4] = NATIVE_TO_PROC (data->temp.hyst); - *nrels_mag = 5; - } else if (operation == SENSORS_PROC_REAL_WRITE && *nrels_mag == 4) { - data->temp.high = PROC_TO_NATIVE (results[0]); - data->temp.low = PROC_TO_NATIVE (results[1]); - data->temp.crit = PROC_TO_NATIVE (results[2]); - data->temp.hyst = PROC_TO_NATIVE (results[3]); - lm92_write (client); - } else if (operation == SENSORS_PROC_REAL_INFO) { - *nrels_mag = 4; - } - - up (&mutex); - } -} - -static void lm92_alarms (struct i2c_client *client,int operation,int ctl_name,int *nrels_mag,long *results) -{ - if (!down_interruptible (&mutex)) { - lm92_t *data = (lm92_t *) client->data; - - if (operation == SENSORS_PROC_REAL_READ) { - lm92_read (client); - results[0] = data->alarms.high || (data->alarms.low << 1) || (data->alarms.crit << 2); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_INFO) { - *nrels_mag = 0; - } - - up (&mutex); - } -} - -static int max6635_check(struct i2c_client *client) -{ - int i; - u16 temp_low, temp_high, temp_hyst, temp_crit; - u8 conf; - - temp_low = i2c_smbus_read_word_data(client, LM92_REG_TRIP_LOW); - temp_high = i2c_smbus_read_word_data(client, LM92_REG_TRIP_HIGH); - temp_hyst = i2c_smbus_read_word_data(client, LM92_REG_TRIP_HYSTERESIS); - temp_crit = i2c_smbus_read_word_data(client, LM92_REG_TRIP_CRITICAL); - - if ((temp_low & 0x7f00) || (temp_high & 0x7f00) - || (temp_hyst & 0x7f00) || (temp_crit & 0x7f00)) - return 0; - - conf = i2c_smbus_read_byte_data(client, LM92_REG_CONFIGURATION); - - for (i=0; i<128; i+=16) { - if (temp_low != i2c_smbus_read_word_data(client, LM92_REG_TRIP_LOW + i) - || temp_high != i2c_smbus_read_word_data(client, LM92_REG_TRIP_HIGH + i) - || temp_hyst != i2c_smbus_read_word_data(client, LM92_REG_TRIP_HYSTERESIS + i) - || temp_crit != i2c_smbus_read_word_data(client, LM92_REG_TRIP_CRITICAL + i) - || conf != i2c_smbus_read_byte_data(client, LM92_REG_CONFIGURATION + i)) - return 0; - } - - return 1; -} - -static int lm92_init_client (struct i2c_client *client) -{ - lm92_t *data = (lm92_t *) client->data; - u8 value = 0; - int result; - - /* force reads to query the chip */ - data->timestamp = 0; - - /* setup the configuration register */ - -#ifdef ENABLE_FAULT_QUEUE - value |= 0x10; -#endif /* #ifdef ENABLE_FAULT_QUEUE */ - - if (lm92_write8 (client,LM92_REG_CONFIGURATION,value) < 0) - return (-ENODEV); - - /* set default alarm trigger values */ - - data->temp.high = CELSIUS (64); - data->temp.low = CELSIUS (10); - data->temp.crit = CELSIUS (80); - data->temp.hyst = CELSIUS (2); - - if ((result = lm92_write (client)) < 0) - return (result); - - /* read everything once so that our cached data is updated */ - - if ((result = lm92_read (client)) < 0) - return (result); - - return (0); -} - -static int lm92_detect (struct i2c_adapter *adapter,int address,unsigned short flags,int kind) -{ - struct i2c_client *client; - lm92_t *data; - int result = 0; - u16 manufacturer; - - if (!i2c_check_functionality (adapter,I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - if (!(data = kmalloc(sizeof(lm92_t), GFP_KERNEL))) - return (-ENOMEM); - - client = &data->client; - client->addr = address; - client->data = data; - client->adapter = adapter; - client->driver = &lm92_driver; - client->flags = 0; - strcpy (client->name,lm92_driver.name); - - if (down_interruptible (&mutex)) { - result = -ERESTARTSYS; - goto ERROR1; - } - - if (kind < 0) { - /* Is it an lm92? */ - if (address < 0x4c - && (lm92_read16(client,LM92_REG_MANUFACTURER,&manufacturer) < 0 - || manufacturer != LM92_MANUFACTURER_ID)) { - /* Is it a MAX6635/MAX6635/MAX6635? */ - if (!max6635_check(client)) { - goto ERROR2; - } - } - } - - if ((result = i2c_attach_client (client))) { - goto ERROR2; - } - - if ((result = i2c_register_entry(client, client->name, lm92_dir_table, - THIS_MODULE)) < 0) { - goto ERROR3; - } - data->sysctl_id = result; - - if ((result = lm92_init_client (client)) < 0) { - goto ERROR4; - } - - up (&mutex); - - return (0); - -ERROR4: - i2c_deregister_entry(data->sysctl_id); -ERROR3: - i2c_detach_client(client); -ERROR2: - up(&mutex); -ERROR1: - kfree(data); - return result; -} - -static int lm92_attach_adapter (struct i2c_adapter *adapter) -{ - return i2c_detect (adapter,&addr_data,lm92_detect); -} - -static int lm92_detach_client (struct i2c_client *client) -{ - int result; - - i2c_deregister_entry (((lm92_t *) (client->data))->sysctl_id); - - if ((result = i2c_detach_client (client))) - return (result); - - kfree(client->data); - - return (0); -} - - -static struct i2c_driver lm92_driver = { - .name = "lm92", - .id = I2C_DRIVERID_LM92, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm92_attach_adapter, - .detach_client = lm92_detach_client, -}; - -static int __init sm_lm92_init(void) -{ - printk ("lm92.o version %s (%s)\n",LM_VERSION,LM_DATE); - return i2c_add_driver(&lm92_driver); -} - - -static void __exit sm_lm92_exit(void) -{ - i2c_del_driver(&lm92_driver); -} - - - -MODULE_AUTHOR ("Abraham van der Merwe "); -MODULE_DESCRIPTION ("Linux support for LM92 Temperature Sensor"); - -MODULE_LICENSE ("GPL"); - -module_init(sm_lm92_init); -module_exit(sm_lm92_exit); - diff --git a/kernel/chips/lm93.c b/kernel/chips/lm93.c deleted file mode 100644 index fe1e3b63..00000000 --- a/kernel/chips/lm93.c +++ /dev/null @@ -1,2343 +0,0 @@ -/* - lm93.c - Part of lm_sensors, Linux kernel modules for hardware monitoring - - Author/Maintainer: Mark M. Hoffman - Copyright (c) 2004 Utilitek Systems, Inc. - - derived in part from lm78.c: - Copyright (c) 1998, 1999 Frodo Looijaard - - derived in part from lm85.c: - Copyright (c) 2002, 2003 Philip Pokorny - Copyright (c) 2003 Margit Schubert-While - - derived in part from w83l785ts.c: - Copyright (c) 2003-2004 Jean Delvare - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#define DEBUG 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" -#include "lm93.h" - -#ifndef I2C_DRIVERID_LM93 -#define I2C_DRIVERID_LM93 1049 -#endif - -/* I2C addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, SENSORS_I2C_END }; - -/* ISA addresses to scan (none) */ -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* module parameters */ -SENSORS_INSMOD_1(lm93); - -static int disable_block /* = 0 */ ; -MODULE_PARM(disable_block, "i"); -MODULE_PARM_DESC(disable_block, - "Set to non-zero to disable SMBus block data transactions."); - -static int init = 1; -MODULE_PARM(init, "i"); -MODULE_PARM_DESC(init, "Set to zero to bypass most chip initialization"); - -static int vccp_limit_type[2] /* = {0,0} */ ; -MODULE_PARM(vccp_limit_type, "2-2i"); -MODULE_PARM_DESC(vccp_limit_type, "Configures in7 and in8 limit modes"); - -static int vid_agtl = 0; -MODULE_PARM(vid_agtl, "i"); -MODULE_PARM_DESC(vid_agtl, "Configures VID pin input thresholds"); - -/* -- SENSORS SYSCTL START -- */ -/* volts * 100 */ -#define LM93_SYSCTL_IN1 1001 -#define LM93_SYSCTL_IN2 1002 -#define LM93_SYSCTL_IN3 1003 -#define LM93_SYSCTL_IN4 1004 -#define LM93_SYSCTL_IN5 1005 -#define LM93_SYSCTL_IN6 1006 -#define LM93_SYSCTL_IN7 1007 -#define LM93_SYSCTL_IN8 1008 -#define LM93_SYSCTL_IN9 1009 -#define LM93_SYSCTL_IN10 1010 -#define LM93_SYSCTL_IN11 1011 -#define LM93_SYSCTL_IN12 1012 -#define LM93_SYSCTL_IN13 1013 -#define LM93_SYSCTL_IN14 1014 -#define LM93_SYSCTL_IN15 1015 -#define LM93_SYSCTL_IN16 1016 - -/* degrees Celsius * 10 */ -#define LM93_SYSCTL_TEMP1 1101 -#define LM93_SYSCTL_TEMP2 1102 -#define LM93_SYSCTL_TEMP3 1103 - -#define LM93_SYSCTL_TEMP1_AUTO_BASE 1111 -#define LM93_SYSCTL_TEMP2_AUTO_BASE 1112 -#define LM93_SYSCTL_TEMP3_AUTO_BASE 1113 - -#define LM93_SYSCTL_TEMP1_AUTO_OFFSETS 1121 -#define LM93_SYSCTL_TEMP2_AUTO_OFFSETS 1122 -#define LM93_SYSCTL_TEMP3_AUTO_OFFSETS 1123 - -#define LM93_SYSCTL_TEMP1_AUTO_BOOST 1131 -#define LM93_SYSCTL_TEMP2_AUTO_BOOST 1132 -#define LM93_SYSCTL_TEMP3_AUTO_BOOST 1133 - -#define LM93_SYSCTL_TEMP1_AUTO_BOOST_HYST 1141 -#define LM93_SYSCTL_TEMP2_AUTO_BOOST_HYST 1142 -#define LM93_SYSCTL_TEMP3_AUTO_BOOST_HYST 1143 - -/* 0 => off, 255 => 100% */ -#define LM93_SYSCTL_TEMP1_AUTO_PWM_MIN 1151 -#define LM93_SYSCTL_TEMP2_AUTO_PWM_MIN 1152 -#define LM93_SYSCTL_TEMP3_AUTO_PWM_MIN 1153 - -/* degrees Celsius * 10 */ -#define LM93_SYSCTL_TEMP1_AUTO_OFFSET_HYST 1161 -#define LM93_SYSCTL_TEMP2_AUTO_OFFSET_HYST 1162 -#define LM93_SYSCTL_TEMP3_AUTO_OFFSET_HYST 1163 - -/* rotations/minute */ -#define LM93_SYSCTL_FAN1 1201 -#define LM93_SYSCTL_FAN2 1202 -#define LM93_SYSCTL_FAN3 1203 -#define LM93_SYSCTL_FAN4 1204 - -/* 1-2 => enable smart tach mode associated with this pwm #, or disable */ -#define LM93_SYSCTL_FAN1_SMART_TACH 1205 -#define LM93_SYSCTL_FAN2_SMART_TACH 1206 -#define LM93_SYSCTL_FAN3_SMART_TACH 1207 -#define LM93_SYSCTL_FAN4_SMART_TACH 1208 - -/* volts * 1000 */ -#define LM93_SYSCTL_VID1 1301 -#define LM93_SYSCTL_VID2 1302 - -/* 0 => off, 255 => 100% */ -#define LM93_SYSCTL_PWM1 1401 -#define LM93_SYSCTL_PWM2 1402 - -/* Hz */ -#define LM93_SYSCTL_PWM1_FREQ 1411 -#define LM93_SYSCTL_PWM2_FREQ 1412 - -/* bitvector */ -#define LM93_SYSCTL_PWM1_AUTO_CHANNELS 1421 -#define LM93_SYSCTL_PWM2_AUTO_CHANNELS 1422 - -/* Hz */ -#define LM93_SYSCTL_PWM1_AUTO_SPINUP_MIN 1431 -#define LM93_SYSCTL_PWM2_AUTO_SPINUP_MIN 1432 - -/* seconds */ -#define LM93_SYSCTL_PWM1_AUTO_SPINUP_TIME 1441 -#define LM93_SYSCTL_PWM2_AUTO_SPINUP_TIME 1442 - -/* seconds */ -#define LM93_SYSCTL_PWM_AUTO_PROCHOT_RAMP 1451 -#define LM93_SYSCTL_PWM_AUTO_VRDHOT_RAMP 1452 - -/* 0 => 0%, 255 => > 99.6% */ -#define LM93_SYSCTL_PROCHOT1 1501 -#define LM93_SYSCTL_PROCHOT2 1502 - -/* !0 => enable #PROCHOT logical short */ -#define LM93_SYSCTL_PROCHOT_SHORT 1503 - -/* 2 boolean enable/disable, 3rd value indicates duty cycle */ -#define LM93_SYSCTL_PROCHOT_OVERRIDE 1504 - -/* 2 values, 0-9 */ -#define LM93_SYSCTL_PROCHOT_INTERVAL 1505 - -/* GPIO input (bitmask) */ -#define LM93_SYSCTL_GPIO 1601 - -/* #VRDHOT input (boolean) */ -#define LM93_SYSCTL_VRDHOT1 1701 -#define LM93_SYSCTL_VRDHOT2 1702 - -/* alarms (bitmask) */ -#define LM93_SYSCTL_ALARMS 2001 - -/* alarm bitmask definitions - The LM93 has nearly 64 bits of error status... I've pared that down to - what I think is a useful subset in order to fit it into 32 bits. - - Especially note that the #VRD_HOT alarms are missing because we provide - that information as values in another /proc file. - - If libsensors is extended to support 64 bit values, this could be revisited. -*/ -#define LM93_ALARM_IN1 0x00000001 -#define LM93_ALARM_IN2 0x00000002 -#define LM93_ALARM_IN3 0x00000004 -#define LM93_ALARM_IN4 0x00000008 -#define LM93_ALARM_IN5 0x00000010 -#define LM93_ALARM_IN6 0x00000020 -#define LM93_ALARM_IN7 0x00000040 -#define LM93_ALARM_IN8 0x00000080 -#define LM93_ALARM_IN9 0x00000100 -#define LM93_ALARM_IN10 0x00000200 -#define LM93_ALARM_IN11 0x00000400 -#define LM93_ALARM_IN12 0x00000800 -#define LM93_ALARM_IN13 0x00001000 -#define LM93_ALARM_IN14 0x00002000 -#define LM93_ALARM_IN15 0x00004000 -#define LM93_ALARM_IN16 0x00008000 -#define LM93_ALARM_FAN1 0x00010000 -#define LM93_ALARM_FAN2 0x00020000 -#define LM93_ALARM_FAN3 0x00040000 -#define LM93_ALARM_FAN4 0x00080000 -#define LM93_ALARM_PH1_ERR 0x00100000 -#define LM93_ALARM_PH2_ERR 0x00200000 -#define LM93_ALARM_SCSI1_ERR 0x00400000 -#define LM93_ALARM_SCSI2_ERR 0x00800000 -#define LM93_ALARM_DVDDP1_ERR 0x01000000 -#define LM93_ALARM_DVDDP2_ERR 0x02000000 -#define LM93_ALARM_D1_ERR 0x04000000 -#define LM93_ALARM_D2_ERR 0x08000000 -#define LM93_ALARM_TEMP1 0x10000000 -#define LM93_ALARM_TEMP2 0x20000000 -#define LM93_ALARM_TEMP3 0x40000000 - -/* -- SENSORS SYSCTL END -- */ - -/* SMBus capabilities */ -#define LM93_SMBUS_FUNC_FULL (I2C_FUNC_SMBUS_BYTE_DATA | \ - I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA) -#define LM93_SMBUS_FUNC_MIN (I2C_FUNC_SMBUS_BYTE_DATA | \ - I2C_FUNC_SMBUS_WORD_DATA) - -/* LM93 BLOCK READ COMMANDS */ -static const struct { u8 cmd; u8 len; } lm93_block_read_cmds[12] = { - { 0xf2, 8 }, - { 0xf3, 8 }, - { 0xf4, 6 }, - { 0xf5, 16 }, - { 0xf6, 4 }, - { 0xf7, 8 }, - { 0xf8, 12 }, - { 0xf9, 32 }, - { 0xfa, 8 }, - { 0xfb, 8 }, - { 0xfc, 16 }, - { 0xfd, 9 }, -}; - -/* ALARMS: SYSCTL format described further below - REG: 64 bits in 8 registers, as immediately below */ -struct block1_t { - u8 host_status_1; - u8 host_status_2; - u8 host_status_3; - u8 host_status_4; - u8 p1_prochot_status; - u8 p2_prochot_status; - u8 gpi_status; - u8 fan_status; -}; - -/* unique ID for each LM93 detected */ -static int lm93_id = 0; - -/* For each registered client, we need to keep some data in memory. That - data is pointed to by client->data. The structure itself is dynamically - allocated, at the same time the client itself is allocated. */ - -struct lm93_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - unsigned long last_updated; /* In jiffies */ - - /* client update function */ - void (*update)(struct lm93_data *, struct i2c_client *); - - char valid; /* !=0 if following fields are valid */ - - /* register values, arranged by block read groups */ - struct block1_t block1; - - /* temp1 - temp4: unfiltered readings - temp1 - temp2: filtered readings */ - u8 block2[6]; - - /* vin1 - vin16: readings */ - u8 block3[16]; - - /* prochot1 - prochot2: readings */ - struct { u8 cur; u8 avg; } block4[2]; - - /* fan counts 1-4 => 14-bits, LE, *left* justified */ - u16 block5[4]; - - /* block6 has a lot of data we don't need */ - struct { u8 min; u8 max; } temp_lim[3]; - - /* vin1 - vin16: low and high limits */ - struct { u8 min; u8 max; } block7[16]; - - /* fan count limits 1-4 => same format as block5 */ - u16 block8[4]; - - /* pwm control registers (2 pwms, 4 regs) */ - u8 block9[2][4]; - - /* auto/pwm base temp and offset temp registers */ - struct { u8 base[4]; u8 offset[12]; } block10; - - /* master config register */ - u8 config; - - /* VID1 & VID2 => register format, 6-bits, right justified */ - u8 vid[2]; - - /* prochot1 - prochot2: limits */ - u8 prochot_max[2]; - - /* vccp1 & vccp2 (in7 & in8): VID relative limits (register format) */ - u8 vccp_limits[2]; - - /* GPIO input state (register format, i.e. inverted) */ - u8 gpi; - - /* #PROCHOT override (register format) */ - u8 prochot_override; - - /* #PROCHOT intervals (register format) */ - u8 prochot_interval; - - /* Fan Boost Temperatures (register format) */ - u8 boost[4]; - - /* Fan Boost Hysteresis (register format) */ - u8 boost_hyst[2]; - - /* Temperature Zone Min. PWM & Hysteresis (register format) */ - u8 auto_pwm_min_hyst[2]; - - /* #PROCHOT & #VRDHOT PWM Ramp Control */ - u8 pwm_ramp_ctl; - - /* miscellaneous setup regs */ - u8 sfc1; - u8 sfc2; - u8 sf_tach_to_pwm; - - /* The two PWM CTL2 registers can read something other than what was - last written for the OVR_DC field (duty cycle override). So, we - save the user-commanded value here. */ - u8 pwm_override[2]; -}; - -#define MAX_RETRIES 5 - -static u8 lm93_read_byte(struct i2c_client *client, u8 reg) -{ - int value, i; - - /* retry in case of read errors */ - for (i=1; i<=MAX_RETRIES; i++) { - if ((value = i2c_smbus_read_byte_data(client, reg)) >= 0) { - return value; - } else { - printk(KERN_WARNING "lm93.o: read byte data failed, " - "address 0x%02x.\n", reg); - mdelay(i + 3); - } - - } - - /* what to return in case of error? */ - printk(KERN_ERR "lm93.o: All read byte retries failed!!\n"); - return 0; -} - -static int lm93_write_byte(struct i2c_client *client, u8 reg, u8 value) -{ - int result; - - /* how to handle write errors? */ - result = i2c_smbus_write_byte_data(client, reg, value); - - if (result < 0) - printk(KERN_WARNING "lm93.o: write byte data failed, " - "0x%02x at address 0x%02x.\n", value, reg); - - return result; -} - -static u16 lm93_read_word(struct i2c_client *client, u8 reg) -{ - int value, i; - - /* retry in case of read errors */ - for (i=1; i<=MAX_RETRIES; i++) { - if ((value = i2c_smbus_read_word_data(client, reg)) >= 0) { - return value; - } else { - printk(KERN_WARNING "lm93.o: read word data failed, " - "address 0x%02x.\n", reg); - mdelay(i + 3); - } - - } - - /* what to return in case of error? */ - printk(KERN_ERR "lm93.o: All read word retries failed!!\n"); - return 0; -} - -static int lm93_write_word(struct i2c_client *client, u8 reg, u16 value) -{ - int result; - - /* how to handle write errors? */ - result = i2c_smbus_write_word_data(client, reg, value); - - if (result < 0) - printk(KERN_WARNING "lm93.o: write word data failed, " - "0x%04x at address 0x%02x.\n", value, reg); - - return result; -} - -static u8 lm93_block_buffer[I2C_SMBUS_BLOCK_MAX]; - -/* - read block data into values, retry if not expected length - fbn => index to lm93_block_read_cmds table - (Fixed Block Number - section 14.5.2 of LM93 datasheet) -*/ -static void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values) -{ - int i, result=0; - - for (i = 1; i <= MAX_RETRIES; i++) { - result = i2c_smbus_read_block_data(client, - lm93_block_read_cmds[fbn].cmd, lm93_block_buffer); - - if (result == lm93_block_read_cmds[fbn].len) { - break; - } else { - printk(KERN_WARNING "lm93.o: block read data failed, " - "command 0x%02x.\n", - lm93_block_read_cmds[fbn].cmd); - mdelay(i + 3); - } - } - - if (result == lm93_block_read_cmds[fbn].len) { - memcpy(values,lm93_block_buffer,lm93_block_read_cmds[fbn].len); - } else { - /* what to do in case of error? */ - } -} - -static void lm93_update_client(struct i2c_client *client) -{ - struct lm93_data *data = client->data; - - down(&data->update_lock); - - if (time_after(jiffies - data->last_updated, HZ + HZ / 2) || - time_before(jiffies, data->last_updated) || !data->valid) { - - data->update(data, client); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -/* update routine for data that has no corresponding SMBus block data command */ -static void lm93_update_client_common(struct lm93_data *data, - struct i2c_client *client) -{ - int i; - u8 *ptr; - - /* temp1 - temp4: limits */ - for (i = 0; i < 4; i++) { - data->temp_lim[i].min = - lm93_read_byte(client, LM93_REG_TEMP_MIN(i)); - data->temp_lim[i].max = - lm93_read_byte(client, LM93_REG_TEMP_MAX(i)); - } - - /* config register */ - data->config = lm93_read_byte(client, LM93_REG_CONFIG); - - /* vid1 - vid2: values */ - for (i = 0; i < 2; i++) - data->vid[i] = lm93_read_byte(client, LM93_REG_VID(i)); - - /* prochot1 - prochot2: limits */ - for (i = 0; i < 2; i++) - data->prochot_max[i] = lm93_read_byte(client, - LM93_REG_PROCHOT_MAX(i)); - - /* vccp1 - vccp2: VID relative limits */ - for (i = 0; i < 2; i++) - data->vccp_limits[i] = lm93_read_byte(client, - LM93_REG_VCCP_LIMIT_OFF(i)); - - /* GPIO input state */ - data->gpi = lm93_read_byte(client, LM93_REG_GPI); - - /* #PROCHOT override state */ - data->prochot_override = lm93_read_byte(client, - LM93_REG_PROCHOT_OVERRIDE); - - /* #PROCHOT intervals */ - data->prochot_interval = lm93_read_byte(client, - LM93_REG_PROCHOT_INTERVAL); - - /* Fan Boost Termperature registers */ - for (i = 0; i < 4; i++) - data->boost[i] = lm93_read_byte(client, LM93_REG_BOOST(i)); - - /* Fan Boost Temperature Hyst. registers */ - data->boost_hyst[0] = lm93_read_byte(client, LM93_REG_BOOST_HYST_12); - data->boost_hyst[1] = lm93_read_byte(client, LM93_REG_BOOST_HYST_34); - - /* Temperature Zone Min. PWM & Hysteresis registers */ - data->auto_pwm_min_hyst[0] = - lm93_read_byte(client, LM93_REG_PWM_MIN_HYST_12); - data->auto_pwm_min_hyst[1] = - lm93_read_byte(client, LM93_REG_PWM_MIN_HYST_34); - - /* #PROCHOT & #VRDHOT PWM Ramp Control register */ - data->pwm_ramp_ctl = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL); - - /* misc setup registers */ - data->sfc1 = lm93_read_byte(client, LM93_REG_SFC1); - data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); - data->sf_tach_to_pwm = lm93_read_byte(client, - LM93_REG_SF_TACH_TO_PWM); - - /* write back alarm values to clear */ - for (i = 0, ptr = (u8 *)(&data->block1); i < 8; i++) - lm93_write_byte(client, LM93_REG_HOST_ERROR_1 + i, *(ptr + i)); -} - -/* update routine which uses SMBus block data commands */ -static void lm93_update_client_full(struct lm93_data *data, - struct i2c_client *client) -{ - pr_debug("lm93.o: starting device update (block data enabled)\n"); - - /* in1 - in16: values & limits */ - lm93_read_block(client, 3, (u8 *)(data->block3)); - lm93_read_block(client, 7, (u8 *)(data->block7)); - - /* temp1 - temp4: values */ - lm93_read_block(client, 2, (u8 *)(data->block2)); - - /* prochot1 - prochot2: values */ - lm93_read_block(client, 4, (u8 *)(data->block4)); - - /* fan1 - fan4: values & limits */ - lm93_read_block(client, 5, (u8 *)(data->block5)); - lm93_read_block(client, 8, (u8 *)(data->block8)); - - /* pmw control registers */ - lm93_read_block(client, 9, (u8 *)(data->block9)); - - /* alarm values */ - lm93_read_block(client, 1, (u8 *)(&data->block1)); - - /* auto/pwm registers */ - lm93_read_block(client, 10, (u8 *)(&data->block10)); - - lm93_update_client_common(data, client); -} - -/* update routine which uses SMBus byte/word data commands only */ -static void lm93_update_client_min(struct lm93_data *data, - struct i2c_client *client) -{ - int i,j; - u8 *ptr; - - pr_debug("lm93.o: starting device update (block data disabled)\n"); - - /* in1 - in16: values & limits */ - for (i = 0; i < 16; i++) { - data->block3[i] = - lm93_read_byte(client, LM93_REG_IN(i)); - data->block7[i].min = - lm93_read_byte(client, LM93_REG_IN_MIN(i)); - data->block7[i].max = - lm93_read_byte(client, LM93_REG_IN_MAX(i)); - } - - /* temp1 - temp4: values */ - for (i = 0; i < 4; i++) { - data->block2[i] = - lm93_read_byte(client, LM93_REG_TEMP(i)); - } - - /* prochot1 - prochot2: values */ - for (i = 0; i < 2; i++) { - data->block4[i].cur = - lm93_read_byte(client, LM93_REG_PROCHOT_CUR(i)); - data->block4[i].avg = - lm93_read_byte(client, LM93_REG_PROCHOT_AVG(i)); - } - - /* fan1 - fan4: values & limits */ - for (i = 0; i < 4; i++) { - data->block5[i] = - lm93_read_word(client, LM93_REG_FAN(i)); - data->block8[i] = - lm93_read_word(client, LM93_REG_FAN_MIN(i)); - } - - /* pwm control registers */ - for (i = 0; i < 2; i++) { - for (j = 0; j < 4; j++) { - data->block9[i][j] = - lm93_read_byte(client, LM93_REG_PWM_CTL(i,j)); - } - } - - /* alarm values */ - for (i = 0, ptr = (u8 *)(&data->block1); i < 8; i++) { - *(ptr + i) = - lm93_read_byte(client, LM93_REG_HOST_ERROR_1 + i); - } - - /* auto/pwm (base temp) registers */ - for (i = 0; i < 4; i++) { - data->block10.base[i] = - lm93_read_byte(client, LM93_REG_TEMP_BASE(i)); - } - - /* auto/pwm (offset temp) registers */ - for (i = 0; i < 12; i++) { - data->block10.offset[i] = - lm93_read_byte(client, LM93_REG_TEMP_OFFSET(i)); - } - - lm93_update_client_common(data, client); -} - -/* VID: mV - REG: 6-bits, right justified, *always* using Intel VRM/VRD 10 */ -static int LM93_VID_FROM_REG(u8 reg) -{ - return vid_from_reg((reg & 0x3f), 100); -} - -static void lm93_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_VID1; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_VID_FROM_REG(data->vid[nr]); - *nrels_mag = 1; - } -} - -/* min, max, and nominal voltage readings, per channel (mV)*/ -static const unsigned long lm93_vin_val_min[16] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 3000, -}; -static const unsigned long lm93_vin_val_max[16] = { - 1236, 1236, 1236, 1600, 2000, 2000, 1600, 1600, - 4400, 6500, 3333, 2625, 1312, 1312, 1236, 3600, -}; -/* -static const unsigned long lm93_vin_val_nom[16] = { - 927, 927, 927, 1200, 1500, 1500, 1200, 1200, - 3300, 5000, 2500, 1969, 984, 984, 309, 3300, -}; -*/ - -/* min, max, and nominal register values, per channel (u8) */ -static const u8 lm93_vin_reg_min[16] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, -}; -static const u8 lm93_vin_reg_max[16] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd1, -}; -/* -static const u8 lm93_vin_reg_nom[16] = { - 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, - 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x40, 0xc0, -}; -*/ - -/* IN: 1/100 V, limits determined by channel nr - REG: scaling determined by channel nr */ -static u8 LM93_IN_TO_REG(int nr, unsigned val) -{ - /* range limit */ - const long mV = SENSORS_LIMIT(val * 10, - lm93_vin_val_min[nr], lm93_vin_val_max[nr]); - - /* try not to lose too much precision here */ - const long uV = mV * 1000; - const long uV_max = lm93_vin_val_max[nr] * 1000; - const long uV_min = lm93_vin_val_min[nr] * 1000; - - /* convert */ - const long slope = (uV_max - uV_min) / - (lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]); - const long intercept = uV_min - slope * lm93_vin_reg_min[nr]; - - u8 result = ((uV - intercept + (slope/2)) / slope); - result = SENSORS_LIMIT(result, - lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]); - return result; -} - -static unsigned LM93_IN_FROM_REG(int nr, u8 reg) -{ - const long uV_max = lm93_vin_val_max[nr] * 1000; - const long uV_min = lm93_vin_val_min[nr] * 1000; - - const long slope = (uV_max - uV_min) / - (lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]); - const long intercept = uV_min - slope * lm93_vin_reg_min[nr]; - - return (slope * reg + intercept + 5000) / 10000; -} - -/* vid in mV , upper == 0 indicates low limit, otherwise upper limit - upper also determines which nibble of the register is returned - (the other nibble will be 0x0) */ -static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid) -{ - long uV_offset = vid * 1000 - val * 10000; - if (upper) { - uV_offset = SENSORS_LIMIT(uV_offset, 12500, 200000); - return (u8)((uV_offset / 12500 - 1) << 4); - } else { - uV_offset = SENSORS_LIMIT(uV_offset, -400000, -25000); - return (u8)((uV_offset / -25000 - 1) << 0); - } -} - -/* vid in mV, upper == 0 indicates low limit, otherwise upper limit */ -static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid) -{ - const long uV_offset = upper ? (((reg >> 4 & 0x0f) + 1) * 12500) : - (((reg >> 0 & 0x0f) + 1) * -25000); - const long uV_vid = vid * 1000; - return (uV_vid + uV_offset + 5000) / 10000; -} - -static void lm93_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_IN1; /* 0 <= nr <= 15 */ - int vccp = ctl_name - LM93_SYSCTL_IN7; /* 0 <= vccp <= 1 if relevant */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - - lm93_update_client(client); - - /* for limits, check in7 and in8 for VID relative mode */ - if ((ctl_name==LM93_SYSCTL_IN7 || ctl_name==LM93_SYSCTL_IN8) && - (vccp_limit_type[vccp])) { - long vid = LM93_VID_FROM_REG(data->vid[vccp]); - results[0] = LM93_IN_REL_FROM_REG( - data->vccp_limits[vccp], 0, vid); - results[1] = LM93_IN_REL_FROM_REG( - data->vccp_limits[vccp], 1, vid); - - /* otherwise, use absolute limits */ - } else { - results[0] = LM93_IN_FROM_REG(nr, - data->block7[nr].min); - results[1] = LM93_IN_FROM_REG(nr, - data->block7[nr].max); - } - - results[2] = LM93_IN_FROM_REG(nr, data->block3[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - - /* for limits, check in7 and in8 for VID relative mode */ - if ((ctl_name==LM93_SYSCTL_IN7 || ctl_name==LM93_SYSCTL_IN8) && - (vccp_limit_type[vccp])) { - - long vid = LM93_VID_FROM_REG(data->vid[vccp]); - if (*nrels_mag >= 2) { - data->vccp_limits[vccp] = - (data->vccp_limits[vccp] & 0x0f) | - LM93_IN_REL_TO_REG(results[1], 1, vid); - } - if (*nrels_mag >= 1) { - data->vccp_limits[vccp] = - (data->vccp_limits[vccp] & 0xf0) | - LM93_IN_REL_TO_REG(results[0], 0, vid); - lm93_write_byte(client, - LM93_REG_VCCP_LIMIT_OFF(vccp), - data->vccp_limits[vccp]); - } - - /* otherwise, use absolute limits */ - } else { - if (*nrels_mag >= 1) { - data->block7[nr].min = LM93_IN_TO_REG(nr, - results[0]); - lm93_write_byte(client, LM93_REG_IN_MIN(nr), - data->block7[nr].min); - } - if (*nrels_mag >= 2) { - data->block7[nr].max = LM93_IN_TO_REG(nr, - results[1]); - lm93_write_byte(client, LM93_REG_IN_MAX(nr), - data->block7[nr].max); - } - } - up(&data->update_lock); - } -} - -static unsigned LM93_ALARMS_FROM_REG(struct block1_t b1) -{ - unsigned result; - result = b1.host_status_2 & 0x3f; - - if (vccp_limit_type[0]) - result |= (b1.host_status_4 & 0x10) << 2; - else - result |= b1.host_status_2 & 0x40; - - if (vccp_limit_type[1]) - result |= (b1.host_status_4 & 0x20) << 2; - else - result |= b1.host_status_2 & 0x80; - - result |= b1.host_status_3 << 8; - result |= (b1.fan_status & 0x0f) << 16; - result |= (b1.p1_prochot_status & 0x80) << 13; - result |= (b1.p2_prochot_status & 0x80) << 14; - result |= (b1.host_status_4 & 0xfc) << 20; - result |= (b1.host_status_1 & 0x07) << 28; - return result; -} - -static void lm93_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_ALARMS_FROM_REG(data->block1); - *nrels_mag = 1; - } -} - -#define LM93_TEMP_MIN (-1280) -#define LM93_TEMP_MAX ( 1270) - -/* TEMP: 1/10 degrees C (-128C to +127C) - REG: 1C/bit, two's complement */ -static u8 LM93_TEMP_TO_REG(int temp) -{ - int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX); - ntemp += (ntemp<0 ? -5 : 5); - return (u8)(ntemp / 10); -} - -static int LM93_TEMP_FROM_REG(u8 reg) -{ - return (s8)reg * 10; -} - -static void lm93_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_TEMP1; - - if (0 > nr || nr > 2) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_TEMP_FROM_REG(data->temp_lim[nr].max); - results[1] = LM93_TEMP_FROM_REG(data->temp_lim[nr].min); - results[2] = LM93_TEMP_FROM_REG(data->block2[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag >= 1) { - data->temp_lim[nr].max = LM93_TEMP_TO_REG(results[0]); - lm93_write_byte(client, LM93_REG_TEMP_MAX(nr), - data->temp_lim[nr].max); - } - if (*nrels_mag >= 2) { - data->temp_lim[nr].min = LM93_TEMP_TO_REG(results[1]); - lm93_write_byte(client, LM93_REG_TEMP_MIN(nr), - data->temp_lim[nr].min); - } - up(&data->update_lock); - } -} - -/* Determine 4-bit temperature offset resolution */ -static int LM93_TEMP_OFFSET_MODE_FROM_REG(u8 sfc2, int nr) -{ - /* mode: 0 => 1C/bit, nonzero => 0.5C/bit */ - return sfc2 & (nr < 2 ? 0x10 : 0x20); -} - -#define LM93_TEMP_OFFSET_MIN ( 0) -#define LM93_TEMP_OFFSET_MAX0 (150) -#define LM93_TEMP_OFFSET_MAX1 ( 75) - -/* This function is common to all 4-bit temperature offsets - returns 4 bits right justified - mode 0 => 1C/bit, mode !0 => 0.5C/bit */ -static u8 LM93_TEMP_OFFSET_TO_REG(int off, int mode) -{ - int factor = mode ? 5 : 10; - - off = SENSORS_LIMIT(off, LM93_TEMP_OFFSET_MIN, - mode ? LM93_TEMP_OFFSET_MAX1 : LM93_TEMP_OFFSET_MAX0); - return (u8)((off + factor/2) / factor); -} - -/* This function is common to all 4-bit temperature offsets - reg is 4 bits right justified - mode 0 => 1C/bit, mode !0 => 0.5C/bit */ -static int LM93_TEMP_OFFSET_FROM_REG(u8 reg, int mode) -{ - return (reg & 0x0f) * (mode ? 5 : 10); -} - -/* TEMP: 1/10 degrees C (0C to +15C (mode 0) or +7.5C (mode non-zero)) - REG: 1.0C/bit (mode 0) or 0.5C/bit (mode non-zero) - 0 <= nr <= 3 */ -static u8 LM93_TEMP_AUTO_OFFSET_TO_REG(u8 old, int off, int nr, int mode) -{ - u8 new = LM93_TEMP_OFFSET_TO_REG(off, mode); - - /* temp1-temp2 (nr=0,1) use lower nibble */ - if (nr < 2) - return (old & 0xf0) | (new & 0x0f); - - /* temp3-temp4 (nr=2,3) use upper nibble */ - else - return (new << 4 & 0xf0) | (old & 0x0f); -} - -/* 0 <= nr <= 3 */ -static int LM93_TEMP_AUTO_OFFSET_FROM_REG(u8 reg, int nr, int mode) -{ - /* temp1-temp2 (nr=0,1) use lower nibble */ - if (nr < 2) - return LM93_TEMP_OFFSET_FROM_REG(reg & 0x0f, mode); - - /* temp3-temp4 (nr=2,3) use upper nibble */ - else - return LM93_TEMP_OFFSET_FROM_REG(reg >> 4 & 0x0f, mode); -} - -static void lm93_temp_auto_offsets(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_TEMP1_AUTO_OFFSETS; - int ii; - - if (0 > nr || nr > 2) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - int mode; - lm93_update_client(client); - - /* mode: 0 => 1C/bit, nonzero => 0.5C/bit */ - mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr); - - for (ii = 0; ii < 12; ii++) { - results[ii] = LM93_TEMP_AUTO_OFFSET_FROM_REG( - data->block10.offset[ii], nr, mode); - } - *nrels_mag = 12; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - /* we only care about the first 12 values */ - int nrels = *nrels_mag > 12 ? 12 : *nrels_mag; - - down(&data->update_lock); - - /* force 0.5C/bit mode */ - data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); - data->sfc2 |= ((nr < 2) ? 0x10 : 0x20); - lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); - - for (ii = 0; ii < nrels; ii++) { - data->block10.offset[ii] = LM93_TEMP_AUTO_OFFSET_TO_REG( - data->block10.offset[ii], results[ii], nr, 1); - lm93_write_byte(client, LM93_REG_TEMP_OFFSET(ii), - data->block10.offset[ii]); - } - up(&data->update_lock); - } -} - -/* RPM: (82.5 to 1350000) - REG: 14-bits, LE, *left* justified */ -static u16 LM93_FAN_TO_REG(long rpm) -{ - u16 count, regs; - - if (rpm == 0) { - count = 0x3fff; - } else { - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - count = SENSORS_LIMIT((1350000 + rpm) / rpm, 1, 0x3ffe); - } - - regs = count << 2; - return cpu_to_le16(regs); -} - -static int LM93_FAN_FROM_REG(u16 regs) -{ - const u16 count = le16_to_cpu(regs) >> 2; - return count==0 ? -1 : count==0x3fff ? 0: 1350000 / count; -} - -static void lm93_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_FAN1; - - if (0 > nr || nr > 3) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_FAN_FROM_REG(data->block8[nr]); /* min */ - results[1] = LM93_FAN_FROM_REG(data->block5[nr]); /* val */ - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - data->block8[nr] = LM93_FAN_TO_REG(results[0]); - lm93_write_word(client, LM93_REG_FAN_MIN(nr), - data->block8[nr]); - up(&data->update_lock); - } - } -} - -/* PROCHOT: 0-255, 0 => 0%, 255 => > 96.6% - * REG: (same) */ -static u8 LM93_PROCHOT_TO_REG(long prochot) -{ - prochot = SENSORS_LIMIT(prochot, 0, 255); - return (u8)prochot; -} - -static void lm93_prochot(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_PROCHOT1; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = data->prochot_max[nr]; - results[1] = data->block4[nr].avg; - results[2] = data->block4[nr].avg; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag >= 1) { - data->prochot_max[nr] = LM93_PROCHOT_TO_REG(results[0]); - lm93_write_byte(client, LM93_REG_PROCHOT_MAX(nr), - data->prochot_max[nr]); - } - up(&data->update_lock); - } -} - -/* PROCHOT-OVERRIDE; 0-15, 0 is 6.25%, 15 is 99.88% - * REG: (same) */ -static u8 LM93_PROCHOT_OVERRIDE_TO_REG(int force1, int force2, long prochot) -{ - u8 result = 0; - - result |= force1 ? 0x80 : 0x00; - result |= force2 ? 0x40 : 0x00; - prochot = SENSORS_LIMIT(prochot, 0, 15); - result |= prochot; - return result; -} - -static void lm93_prochot_override(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - - if (ctl_name != LM93_SYSCTL_PROCHOT_OVERRIDE) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = (data->prochot_override & 0x80) ? 1 : 0; - results[1] = (data->prochot_override & 0x40) ? 1 : 0; - results[2] = data->prochot_override & 0x0f; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - - /* grab old values */ - int force2 = (data->prochot_override & 0x40) ? 1 : 0; - int prochot = data->prochot_override & 0x0f; - - down(&data->update_lock); - if (*nrels_mag >= 3) { - data->prochot_override = LM93_PROCHOT_OVERRIDE_TO_REG( - results[0], results[1], results[2]); - } - if (*nrels_mag == 2) { - data->prochot_override = LM93_PROCHOT_OVERRIDE_TO_REG( - results[0], results[1], prochot); - } - if (*nrels_mag == 1) { - data->prochot_override = LM93_PROCHOT_OVERRIDE_TO_REG( - results[0], force2, prochot); - } - if (*nrels_mag >= 1) { - lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE, - data->prochot_override); - } - up(&data->update_lock); - } -} - -/* PROCHOT-INTERVAL: 73 - 37200 (1/100 seconds) - * REG: 0-9 as mapped below */ -static int lm93_interval_map[10] = { - 73, 146, 290, 580, 1170, 2330, 4660, 9320, 18600, 37200, -}; - -static int LM93_INTERVAL_FROM_REG(u8 reg) -{ - return lm93_interval_map[reg & 0x0f]; -} - -/* round up to nearest match */ -static u8 LM93_INTERVAL_TO_REG(long interval) -{ - int i; - for (i = 0; i < 9; i++) - if (interval <= lm93_interval_map[i]) - break; - - /* can fall through with i==9 */ - return (u8)i; -} - -static void lm93_prochot_interval(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - - if (ctl_name != LM93_SYSCTL_PROCHOT_INTERVAL) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_INTERVAL_FROM_REG( - data->prochot_interval & 0x0f); - results[1] = LM93_INTERVAL_FROM_REG( - (data->prochot_interval & 0xf0) >> 4); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - data->prochot_interval = lm93_read_byte(client, - LM93_REG_PROCHOT_INTERVAL); - if (*nrels_mag >= 2) { - data->prochot_interval = - (LM93_INTERVAL_TO_REG(results[1]) << 4) | - (data->prochot_interval & 0x0f); - } - if (*nrels_mag >= 1) { - data->prochot_interval = - (data->prochot_interval & 0xf0) | - LM93_INTERVAL_TO_REG(results[0]); - lm93_write_byte(client, LM93_REG_PROCHOT_INTERVAL, - data->prochot_interval); - } - up(&data->update_lock); - } -} - -/* PWM: 0-255 per sensors documentation - REG: 0-13 as mapped below... right justified */ -typedef enum { LM93_PWM_MAP_HI_FREQ, LM93_PWM_MAP_LO_FREQ } pwm_freq_t; -static int lm93_pwm_map[2][14] = { - { - 0x00, /* 0.00% */ 0x40, /* 25.00% */ - 0x50, /* 31.25% */ 0x60, /* 37.50% */ - 0x70, /* 43.75% */ 0x80, /* 50.00% */ - 0x90, /* 56.25% */ 0xa0, /* 62.50% */ - 0xb0, /* 68.75% */ 0xc0, /* 75.00% */ - 0xd0, /* 81.25% */ 0xe0, /* 87.50% */ - 0xf0, /* 93.75% */ 0xff, /* 100.00% */ - }, - { - 0x00, /* 0.00% */ 0x40, /* 25.00% */ - 0x49, /* 28.57% */ 0x52, /* 32.14% */ - 0x5b, /* 35.71% */ 0x64, /* 39.29% */ - 0x6d, /* 42.86% */ 0x76, /* 46.43% */ - 0x80, /* 50.00% */ 0x89, /* 53.57% */ - 0x92, /* 57.14% */ 0xb6, /* 71.43% */ - 0xdb, /* 85.71% */ 0xff, /* 100.00% */ - }, -}; - -static int LM93_PWM_FROM_REG(u8 reg, pwm_freq_t freq) -{ - return lm93_pwm_map[freq][reg & 0x0f]; -} - -/* round up to nearest match */ -static u8 LM93_PWM_TO_REG(int pwm, pwm_freq_t freq) -{ - int i; - for (i = 0; i < 13; i++) - if (pwm <= lm93_pwm_map[freq][i]) - break; - - /* can fall through with i==13 */ - return (u8)i; -} - -static void lm93_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_PWM1; - u8 ctl2, ctl4; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - ctl2 = data->block9[nr][LM93_PWM_CTL2]; - ctl4 = data->block9[nr][LM93_PWM_CTL4]; - results[1] = (ctl2 & 0x01) ? 1 : 0; - ctl2 = ctl2 >> 4 & 0x0f; - if (results[1]) /* show user commanded value if enabled */ - results[0] = data->pwm_override[nr]; - else /* show present h/w value if manual pwm disabled */ - results[0] = LM93_PWM_FROM_REG(ctl2, (ctl4 & 0x07) ? - LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ); - *nrels_mag = 2; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - ctl2 = lm93_read_byte( - client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2)); - ctl4 = lm93_read_byte( - client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4)); - ctl2 = (ctl2 & 0x0f) | - LM93_PWM_TO_REG(results[0], (ctl4 & 0x07) ? - LM93_PWM_MAP_LO_FREQ : - LM93_PWM_MAP_HI_FREQ) << 4; - if (*nrels_mag >= 2) { - if (results[1]) - ctl2 |= 0x01; - else - ctl2 &= ~0x01; - } - /* save user commanded value */ - data->pwm_override[nr] = - LM93_PWM_FROM_REG(ctl2 >> 4 & 0x0f, - (ctl4 & 0x07) ? LM93_PWM_MAP_LO_FREQ : - LM93_PWM_MAP_HI_FREQ); - lm93_write_byte(client, - LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2), ctl2); - up(&data->update_lock); - } - } -} - -/* PWM FREQ: HZ - REG: 0-7 as mapped below */ -static int lm93_pwm_freq_map[8] = { - 22500, 96, 84, 72, 60, 48, 36, 12 -}; - -static int LM93_PWM_FREQ_FROM_REG(u8 reg) -{ - return lm93_pwm_freq_map[reg & 0x07]; -} - -/* round up to nearest match */ -static u8 LM93_PWM_FREQ_TO_REG(int freq) -{ - int i; - for (i = 7; i > 0; i--) - if (freq <= lm93_pwm_freq_map[i]) - break; - - /* can fall through with i==0 */ - return (u8)i; -} - -/* helper function - must grab data->update_lock before calling - fan is 0-3, indicating fan1-fan4 */ -static void lm93_write_fan_smart_tach(struct i2c_client *client, - struct lm93_data *data, int fan, long value) -{ - /* insert the new mapping and write it out */ - data->sf_tach_to_pwm = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM); - data->sf_tach_to_pwm &= ~(0x3 << fan * 2); - data->sf_tach_to_pwm |= value << fan * 2; - lm93_write_byte(client, LM93_REG_SF_TACH_TO_PWM, data->sf_tach_to_pwm); - - /* insert the enable bit and write it out */ - data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); - if (value) - data->sfc2 |= 1 << fan; - else - data->sfc2 &= ~(1 << fan); - lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); -} - -/* helper function - must grab data->update_lock before calling - pwm is 0-1, indicating pwm1-pwm2 - this disables smart tach for all tach channels bound to the given pwm */ -static void lm93_disable_fan_smart_tach(struct i2c_client *client, - struct lm93_data *data, int pwm) -{ - int mapping = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM); - int mask; - - /* collapse the mapping into a mask of enable bits */ - mapping = (mapping >> pwm) & 0x55; - mask = mapping & 0x01; - mask |= (mapping & 0x04) >> 1; - mask |= (mapping & 0x10) >> 2; - mask |= (mapping & 0x40) >> 3; - - /* disable smart tach according to the mask */ - data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); - data->sfc2 &= ~mask; - lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); -} - -static void lm93_pwm_freq(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_PWM1_FREQ; - u8 ctl4; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - ctl4 = data->block9[nr][LM93_PWM_CTL4]; - results[0] = LM93_PWM_FREQ_FROM_REG(ctl4); - *nrels_mag = 1; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - ctl4 = lm93_read_byte( client, - LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4)); - ctl4 = (ctl4 & 0xf8) | LM93_PWM_FREQ_TO_REG(results[0]); - data->block9[nr][LM93_PWM_CTL4] = ctl4; - - /* ctl4 == 0 -> 22.5KHz -> disable smart tach */ - if (!ctl4) - lm93_disable_fan_smart_tach(client, data, nr); - - lm93_write_byte(client, - LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4), ctl4); - up(&data->update_lock); - } - } -} - -/* GPIO: 0-255, GPIO0 is LSB - * REG: inverted */ -static unsigned LM93_GPI_FROM_REG(u8 reg) -{ - return ~reg & 0xff; -} - -static void lm93_gpio(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - - if (ctl_name != LM93_SYSCTL_GPIO) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_GPI_FROM_REG(data->gpi); - *nrels_mag = 1; - } -} - -static void lm93_temp_auto_base(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_TEMP1_AUTO_BASE; - - if (0 > nr || nr > 2) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_TEMP_FROM_REG(data->block10.base[nr]); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag >= 1) { - data->block10.base[nr] = LM93_TEMP_TO_REG(results[0]); - lm93_write_byte(client, LM93_REG_TEMP_BASE(nr), - data->block10.base[nr]); - } - up(&data->update_lock); - } -} - -static void lm93_temp_auto_boost(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_TEMP1_AUTO_BOOST; - - if (0 > nr || nr > 2) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_TEMP_FROM_REG(data->boost[nr]); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag >= 1) { - data->boost[nr] = LM93_TEMP_TO_REG(results[0]); - lm93_write_byte(client, LM93_REG_BOOST(nr), - data->boost[nr]); - } - up(&data->update_lock); - } - -} - -static u8 LM93_AUTO_BOOST_HYST_TO_REG(struct lm93_data *data, long hyst, - int nr, int mode) -{ - u8 reg = LM93_TEMP_OFFSET_TO_REG( - (LM93_TEMP_FROM_REG(data->boost[nr]) - hyst), mode); - - switch (nr) { - case 0: - reg = (data->boost_hyst[0] & 0xf0) | (reg & 0x0f); - break; - case 1: - reg = (reg << 4 & 0xf0) | (data->boost_hyst[0] & 0x0f); - break; - case 2: - reg = (data->boost_hyst[1] & 0xf0) | (reg & 0x0f); - break; - case 3: - default: - reg = (reg << 4 & 0xf0) | (data->boost_hyst[1] & 0x0f); - break; - } - - return reg; -} - -static int LM93_AUTO_BOOST_HYST_FROM_REGS(struct lm93_data *data, int nr, - int mode) -{ - u8 reg; - - switch (nr) { - case 0: - reg = data->boost_hyst[0] & 0x0f; - break; - case 1: - reg = data->boost_hyst[0] >> 4 & 0x0f; - break; - case 2: - reg = data->boost_hyst[1] & 0x0f; - break; - case 3: - default: - reg = data->boost_hyst[1] >> 4 & 0x0f; - break; - } - - return LM93_TEMP_FROM_REG(data->boost[nr]) - - LM93_TEMP_OFFSET_FROM_REG(reg, mode); -} - -static void lm93_temp_auto_boost_hyst(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_TEMP1_AUTO_BOOST_HYST; - - if (0 > nr || nr > 2) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - int mode; - lm93_update_client(client); - - /* mode: 0 => 1C/bit, nonzero => 0.5C/bit */ - mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr); - - results[0] = LM93_AUTO_BOOST_HYST_FROM_REGS(data, nr, mode); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - - /* force 0.5C/bit mode */ - data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); - data->sfc2 |= ((nr < 2) ? 0x10 : 0x20); - lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); - - data->boost_hyst[nr/2] = - LM93_AUTO_BOOST_HYST_TO_REG(data, - results[0], nr, 1); - lm93_write_byte(client, LM93_REG_BOOST_HYST(nr), - data->boost_hyst[nr/2]); - up(&data->update_lock); - } - } -} - -static void lm93_temp_auto_pwm_min(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_TEMP1_AUTO_PWM_MIN; - u8 reg, ctl4; - - if (0 > nr || nr > 2) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - reg = data->auto_pwm_min_hyst[nr/2] >> 4 & 0x0f; - ctl4 = data->block9[nr][LM93_PWM_CTL4]; - results[0] = LM93_PWM_FROM_REG(reg, (ctl4 & 0x07) ? - LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - reg = lm93_read_byte(client, LM93_REG_PWM_MIN_HYST(nr)); - ctl4 = lm93_read_byte( - client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4)); - reg = (reg & 0x0f) | - LM93_PWM_TO_REG(results[0], (ctl4 & 0x07) ? - LM93_PWM_MAP_LO_FREQ : - LM93_PWM_MAP_HI_FREQ) << 4; - - data->auto_pwm_min_hyst[nr/2] = reg; - lm93_write_byte(client, LM93_REG_PWM_MIN_HYST(nr), reg); - up(&data->update_lock); - } - } -} - -static void lm93_temp_auto_offset_hyst(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_TEMP1_AUTO_OFFSET_HYST; - - if (0 > nr || nr > 2) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - int mode; - lm93_update_client(client); - - /* mode: 0 => 1C/bit, nonzero => 0.5C/bit */ - mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr); - - results[0] = LM93_TEMP_OFFSET_FROM_REG( - data->auto_pwm_min_hyst[nr/2], mode); - - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - u8 reg; - down(&data->update_lock); - - /* force 0.5C/bit mode */ - data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); - data->sfc2 |= ((nr < 2) ? 0x10 : 0x20); - lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); - - reg = data->auto_pwm_min_hyst[nr/2]; - reg = (reg & 0xf0) | - (LM93_TEMP_OFFSET_TO_REG(results[0], 1) & 0x0f); - - data->auto_pwm_min_hyst[nr/2] = reg; - lm93_write_byte(client, LM93_REG_PWM_MIN_HYST(nr), reg); - up(&data->update_lock); - } - } -} - -/* some tedious bit-twiddling here to deal with the register format: - - data->sf_tach_to_pwm: (tach to pwm mapping bits) - - bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 - T4:P2 T4:P1 T3:P2 T3:P1 T2:P2 T2:P1 T1:P2 T1:P1 - - data->sfc2: (enable bits) - - bit | 3 | 2 | 1 | 0 - T4 T3 T2 T1 -*/ - -static void lm93_fan_smart_tach(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_FAN1_SMART_TACH; - - if (0 > nr || nr > 3) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - int mapping; - - lm93_update_client(client); - - /* extract the relevant mapping */ - mapping = (data->sf_tach_to_pwm >> (nr * 2)) & 0x03; - - /* if there's a mapping and it's enabled */ - if (mapping && ((data->sfc2 >> nr) & 0x01)) - results[0] = mapping; - else - results[0] = 0; - - *nrels_mag = 1; - - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - - /* sanity test, ignore the write otherwise */ - if (0 <= results[0] && results[0] <= 2) { - - /* can't enable if pwm freq is 22.5KHz */ - if (results[0]) { - u8 ctl4 = lm93_read_byte(client, - LM93_REG_PWM_CTL(results[0]-1, - LM93_PWM_CTL4)); - if ((ctl4 & 0x07) == 0) - results[0] = 0; - } - - lm93_write_fan_smart_tach(client, data, nr, - results[0]); - } - up(&data->update_lock); - } - } -} - -static void lm93_prochot_short(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - - if (ctl_name != LM93_SYSCTL_PROCHOT_SHORT) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = (data->config & 0x10) ? 1 : 0; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag >= 1) { - if (results[0]) - data->config |= 0x10; - else - data->config &= ~0x10; - lm93_write_byte(client, LM93_REG_CONFIG, data->config); - } - up(&data->update_lock); - } -} - -static void lm93_vrdhot(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_VRDHOT1; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = data->block1.host_status_1 & (1 << (nr+4)) ? 1 : 0; - *nrels_mag = 1; - } -} - -static void lm93_pwm_auto_chan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_PWM1_AUTO_CHANNELS; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = data->block9[nr][LM93_PWM_CTL1]; - *nrels_mag = 1; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - data->block9[nr][LM93_PWM_CTL1] = - SENSORS_LIMIT(results[0], 0, 255); - lm93_write_byte(client, - LM93_REG_PWM_CTL(nr,LM93_PWM_CTL1), - data->block9[nr][LM93_PWM_CTL1]); - up(&data->update_lock); - } - } -} - -static void lm93_pwm_auto_spinup_min(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_PWM1_AUTO_SPINUP_MIN; - u8 ctl3, ctl4; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - ctl3 = data->block9[nr][LM93_PWM_CTL3]; - ctl4 = data->block9[nr][LM93_PWM_CTL4]; - results[0] = LM93_PWM_FROM_REG(ctl3 & 0x0f, (ctl4 & 0x07) ? - LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ); - *nrels_mag = 1; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - ctl3 = lm93_read_byte(client, - LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3)); - ctl4 = lm93_read_byte(client, - LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4)); - ctl3 = (ctl3 & 0xf0) | - LM93_PWM_TO_REG(results[0], (ctl4 & 0x07) ? - LM93_PWM_MAP_LO_FREQ : - LM93_PWM_MAP_HI_FREQ); - data->block9[nr][LM93_PWM_CTL3] = ctl3; - lm93_write_byte(client, - LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3); - up(&data->update_lock); - } - } -} - -/* TIME: 1/100 seconds - * REG: 0-7 as mapped below */ -static int lm93_spinup_time_map[8] = { - 0, 10, 25, 40, 70, 100, 200, 400, -}; - -static int LM93_SPINUP_TIME_FROM_REG(u8 reg) -{ - return lm93_spinup_time_map[reg >> 5 & 0x07]; -} - -/* round up to nearest match */ -static u8 LM93_SPINUP_TIME_TO_REG(int time) -{ - int i; - for (i = 0; i < 7; i++) - if (time <= lm93_spinup_time_map[i]) - break; - - /* can fall through with i==8 */ - return (u8)i; -} - -static void lm93_pwm_auto_spinup_time(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_PWM1_AUTO_SPINUP_TIME; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_SPINUP_TIME_FROM_REG( - data->block9[nr][LM93_PWM_CTL3]); - *nrels_mag = 1; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - u8 ctl3; - down(&data->update_lock); - ctl3 = lm93_read_byte(client, - LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3)); - ctl3 = (ctl3 & 0x1f) | (LM93_SPINUP_TIME_TO_REG( - results[0]) << 5 & 0xe0); - data->block9[nr][LM93_PWM_CTL3] = ctl3; - lm93_write_byte(client, - LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3); - up(&data->update_lock); - } - } -} - -#define LM93_RAMP_MIN 0 -#define LM93_RAMP_MAX 75 - -/* RAMP: 1/100 seconds - REG: 50mS/bit 4-bits right justified */ -static u8 LM93_RAMP_TO_REG(int ramp) -{ - ramp = SENSORS_LIMIT(ramp, LM93_RAMP_MIN, LM93_RAMP_MAX); - return (u8)((ramp + 2) / 5); -} - -static int LM93_RAMP_FROM_REG(u8 reg) -{ - return (reg & 0x0f) * 5; -} - -static void lm93_pwm_auto_ramp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - - if (!(ctl_name == LM93_SYSCTL_PWM_AUTO_PROCHOT_RAMP || - ctl_name == LM93_SYSCTL_PWM_AUTO_VRDHOT_RAMP)) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - if (ctl_name == LM93_SYSCTL_PWM_AUTO_PROCHOT_RAMP) - results[0] = LM93_RAMP_FROM_REG( - data->pwm_ramp_ctl >> 4 & 0x0f); - else - results[0] = LM93_RAMP_FROM_REG( - data->pwm_ramp_ctl & 0x0f); - *nrels_mag = 1; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - u8 ramp; - down(&data->update_lock); - ramp = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL); - if (ctl_name == LM93_SYSCTL_PWM_AUTO_PROCHOT_RAMP) - ramp = (ramp & 0x0f) | (LM93_RAMP_TO_REG( - results[0]) << 4 & 0xf0); - else - ramp = (ramp & 0xf0) | (LM93_RAMP_TO_REG( - results[0]) & 0x0f); - lm93_write_byte(client, LM93_REG_PWM_RAMP_CTL, ramp); - up(&data->update_lock); - } - } -} - -/* These files are created for each detected LM93. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ - -#define LM93_SYSCTL_IN(nr) {LM93_SYSCTL_IN##nr, "in" #nr, NULL, 0, \ - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_in} -#define LM93_SYSCTL_TEMP(nr) {LM93_SYSCTL_TEMP##nr, "temp" #nr, NULL, 0, \ - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_temp} -#define LM93_SYSCTL_TEMP_AUTO_BASE(nr) {LM93_SYSCTL_TEMP##nr##_AUTO_BASE, \ - "temp" #nr "_auto_base", NULL, 0, 0644, NULL, &i2c_proc_real, \ - &i2c_sysctl_real, NULL, &lm93_temp_auto_base} -#define LM93_SYSCTL_TEMP_AUTO_OFFSETS(nr) {LM93_SYSCTL_TEMP##nr##_AUTO_OFFSETS,\ - "temp" #nr "_auto_offsets", NULL, 0, 0644, NULL, &i2c_proc_real, \ - &i2c_sysctl_real, NULL, &lm93_temp_auto_offsets} -#define LM93_SYSCTL_TEMP_AUTO_BOOST(nr) { LM93_SYSCTL_TEMP##nr##_AUTO_BOOST, \ - "temp" #nr "_auto_boost", NULL, 0, 0644, NULL, &i2c_proc_real, \ - &i2c_sysctl_real, NULL, &lm93_temp_auto_boost} -#define LM93_SYSCTL_TEMP_AUTO_BOOST_HYST(nr) { \ - LM93_SYSCTL_TEMP##nr##_AUTO_BOOST_HYST, "temp" #nr "_auto_boost_hyst", \ - NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ - &lm93_temp_auto_boost_hyst} -#define LM93_SYSCTL_TEMP_AUTO_PWM_MIN(nr) { \ - LM93_SYSCTL_TEMP##nr##_AUTO_PWM_MIN, "temp" #nr "_auto_pwm_min", \ - NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ - &lm93_temp_auto_pwm_min} -#define LM93_SYSCTL_TEMP_AUTO_OFFSET_HYST(nr) { \ - LM93_SYSCTL_TEMP##nr##_AUTO_OFFSET_HYST,"temp" #nr "_auto_offset_hyst",\ - NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ - &lm93_temp_auto_offset_hyst} -#define LM93_SYSCTL_PWM(nr) {LM93_SYSCTL_PWM##nr, "pwm" #nr, NULL, 0, \ - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_pwm} -#define LM93_SYSCTL_PWM_FREQ(nr) {LM93_SYSCTL_PWM##nr##_FREQ, \ - "pwm" #nr "_freq", NULL, 0, 0644, NULL, &i2c_proc_real, \ - &i2c_sysctl_real, NULL, &lm93_pwm_freq} -#define LM93_SYSCTL_PWM_AUTO_CHAN(nr) {LM93_SYSCTL_PWM##nr##_AUTO_CHANNELS, \ - "pwm" #nr "_auto_channels", NULL, 0, 0644, NULL, &i2c_proc_real, \ - &i2c_sysctl_real, NULL, &lm93_pwm_auto_chan} -#define LM93_SYSCTL_PWM_AUTO_SPINUP_MIN(nr) { \ - LM93_SYSCTL_PWM##nr##_AUTO_SPINUP_MIN, "pwm" #nr "_auto_spinup_min", \ - NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ - &lm93_pwm_auto_spinup_min} -#define LM93_SYSCTL_PWM_AUTO_SPINUP_TIME(nr) { \ - LM93_SYSCTL_PWM##nr##_AUTO_SPINUP_TIME, "pwm" #nr "_auto_spinup_time", \ - NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ - &lm93_pwm_auto_spinup_time} -#define LM93_SYSCTL_FAN(nr) {LM93_SYSCTL_FAN##nr, "fan" #nr, NULL, 0, \ - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_fan} -#define LM93_SYSCTL_VID(nr) {LM93_SYSCTL_VID##nr, "vid" #nr, NULL, 0, \ - 0444, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_vid} -#define LM93_SYSCTL_PROCHOT(nr) {LM93_SYSCTL_PROCHOT##nr, "prochot" #nr, NULL, \ - 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_prochot} -#define LM93_SYSCTL_VRDHOT(nr) {LM93_SYSCTL_VRDHOT##nr, "vrdhot" #nr, NULL, \ - 0, 0444, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_vrdhot} -#define LM93_SYSCTL_FAN_SMART_TACH(nr) {LM93_SYSCTL_FAN##nr##_SMART_TACH, \ - "fan" #nr "_smart_tach", NULL, 0, 0644, NULL, &i2c_proc_real, \ - &i2c_sysctl_real, NULL, &lm93_fan_smart_tach} -static ctl_table lm93_dir_table_template[] = { - LM93_SYSCTL_IN(1), - LM93_SYSCTL_IN(2), - LM93_SYSCTL_IN(3), - LM93_SYSCTL_IN(4), - LM93_SYSCTL_IN(5), - LM93_SYSCTL_IN(6), - LM93_SYSCTL_IN(7), - LM93_SYSCTL_IN(8), - LM93_SYSCTL_IN(9), - LM93_SYSCTL_IN(10), - LM93_SYSCTL_IN(11), - LM93_SYSCTL_IN(12), - LM93_SYSCTL_IN(13), - LM93_SYSCTL_IN(14), - LM93_SYSCTL_IN(15), - LM93_SYSCTL_IN(16), - - LM93_SYSCTL_TEMP(1), - LM93_SYSCTL_TEMP(2), - LM93_SYSCTL_TEMP(3), - - LM93_SYSCTL_TEMP_AUTO_BASE(1), - LM93_SYSCTL_TEMP_AUTO_BASE(2), - LM93_SYSCTL_TEMP_AUTO_BASE(3), - - LM93_SYSCTL_TEMP_AUTO_OFFSETS(1), - LM93_SYSCTL_TEMP_AUTO_OFFSETS(2), - LM93_SYSCTL_TEMP_AUTO_OFFSETS(3), - - LM93_SYSCTL_TEMP_AUTO_BOOST(1), - LM93_SYSCTL_TEMP_AUTO_BOOST(2), - LM93_SYSCTL_TEMP_AUTO_BOOST(3), - - LM93_SYSCTL_TEMP_AUTO_BOOST_HYST(1), - LM93_SYSCTL_TEMP_AUTO_BOOST_HYST(2), - LM93_SYSCTL_TEMP_AUTO_BOOST_HYST(3), - - LM93_SYSCTL_TEMP_AUTO_PWM_MIN(1), - LM93_SYSCTL_TEMP_AUTO_PWM_MIN(2), - LM93_SYSCTL_TEMP_AUTO_PWM_MIN(3), - - LM93_SYSCTL_TEMP_AUTO_OFFSET_HYST(1), - LM93_SYSCTL_TEMP_AUTO_OFFSET_HYST(2), - LM93_SYSCTL_TEMP_AUTO_OFFSET_HYST(3), - - LM93_SYSCTL_FAN(1), - LM93_SYSCTL_FAN(2), - LM93_SYSCTL_FAN(3), - LM93_SYSCTL_FAN(4), - - LM93_SYSCTL_FAN_SMART_TACH(1), - LM93_SYSCTL_FAN_SMART_TACH(2), - LM93_SYSCTL_FAN_SMART_TACH(3), - LM93_SYSCTL_FAN_SMART_TACH(4), - - LM93_SYSCTL_PWM(1), - LM93_SYSCTL_PWM(2), - - LM93_SYSCTL_PWM_FREQ(1), - LM93_SYSCTL_PWM_FREQ(2), - - LM93_SYSCTL_PWM_AUTO_CHAN(1), - LM93_SYSCTL_PWM_AUTO_CHAN(2), - - LM93_SYSCTL_PWM_AUTO_SPINUP_MIN(1), - LM93_SYSCTL_PWM_AUTO_SPINUP_MIN(2), - - LM93_SYSCTL_PWM_AUTO_SPINUP_TIME(1), - LM93_SYSCTL_PWM_AUTO_SPINUP_TIME(2), - - {LM93_SYSCTL_PWM_AUTO_PROCHOT_RAMP, "pwm_auto_prochot_ramp", NULL, 0, - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, - &lm93_pwm_auto_ramp}, - - {LM93_SYSCTL_PWM_AUTO_VRDHOT_RAMP, "pwm_auto_vrdhot_ramp", NULL, 0, - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, - &lm93_pwm_auto_ramp}, - - LM93_SYSCTL_VID(1), - LM93_SYSCTL_VID(2), - - LM93_SYSCTL_PROCHOT(1), - LM93_SYSCTL_PROCHOT(2), - - {LM93_SYSCTL_PROCHOT_SHORT, "prochot_short", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_prochot_short}, - - {LM93_SYSCTL_PROCHOT_OVERRIDE, "prochot_override", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_prochot_override}, - - {LM93_SYSCTL_PROCHOT_INTERVAL, "prochot_interval", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_prochot_interval}, - - LM93_SYSCTL_VRDHOT(1), - LM93_SYSCTL_VRDHOT(2), - - {LM93_SYSCTL_GPIO, "gpio", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_gpio}, - - {LM93_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm93_alarms}, - - {0} -}; - -static void lm93_init_client(struct i2c_client *client) -{ - int i; - u8 reg; - - /* configure VID pin input thresholds */ - reg = lm93_read_byte(client, LM93_REG_GPI_VID_CTL); - lm93_write_byte(client, LM93_REG_GPI_VID_CTL, - reg | (vid_agtl ? 0x03 : 0x00)); - - if (init) { - /* enable #ALERT pin */ - reg = lm93_read_byte(client, LM93_REG_CONFIG); - lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x08); - - /* enable ASF mode for BMC status registers */ - reg = lm93_read_byte(client, LM93_REG_STATUS_CONTROL); - lm93_write_byte(client, LM93_REG_STATUS_CONTROL, reg | 0x02); - - /* set sleep state to S0 */ - lm93_write_byte(client, LM93_REG_SLEEP_CONTROL, 0); - - /* unmask #VRDHOT and dynamic VCCP (if nec) error events */ - reg = lm93_read_byte(client, LM93_REG_MISC_ERR_MASK); - reg &= ~0x03; - reg &= ~(vccp_limit_type[0] ? 0x10 : 0); - reg &= ~(vccp_limit_type[1] ? 0x20 : 0); - lm93_write_byte(client, LM93_REG_MISC_ERR_MASK, reg); - } - - /* start monitoring */ - reg = lm93_read_byte(client, LM93_REG_CONFIG); - lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x01); - - /* spin until ready */ - for (i=0; i<20; i++) { - mdelay(10); - if ((lm93_read_byte(client, LM93_REG_CONFIG) & 0x80) == 0x80) - return; - } - - printk(KERN_WARNING "lm93.o: timed out waiting for sensor " - "chip to signal ready!\n"); -} - -/* forward declaration */ -static struct i2c_driver lm93_driver; - -/* This function is called by i2c_detect */ -static int lm93_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int err = 0, func; - struct lm93_data *data; - struct i2c_client *client; - void (*update)(struct lm93_data *, struct i2c_client *); - - /* lm93 is SMBus only */ - if (i2c_is_isa_adapter(adapter)) { - pr_debug("lm93.o: detect failed, " - "cannot attach to legacy adapter!\n"); - goto ERROR0; - } - - /* choose update routine based on bus capabilities */ - func = i2c_get_functionality(adapter); - - if ( ((LM93_SMBUS_FUNC_FULL & func) == LM93_SMBUS_FUNC_FULL) && - (!disable_block) ) { - pr_debug("lm93.o: using SMBus block data transactions\n"); - update = lm93_update_client_full; - } else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) { - pr_debug("lm93.o: disabled SMBus block data transactions\n"); - update = lm93_update_client_min; - } else { - pr_debug("lm93.o: detect failed, " - "smbus byte and/or word data not supported!\n"); - goto ERROR0; - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm78_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct lm93_data), GFP_KERNEL))) { - pr_debug("lm93.o: detect failed, kmalloc failed!\n"); - err = -ENOMEM; - goto ERROR0; - } - - client = &data->client; - client->addr = address; - client->data = data; - client->adapter = adapter; - client->driver = &lm93_driver; - client->flags = 0; - - /* detection */ - if (kind < 0) { - int mfr = lm93_read_byte(client, LM93_REG_MFR_ID); - - if (mfr != 0x01) { - pr_debug("lm93.o: detect failed, " - "bad manufacturer id 0x%02x!\n", mfr); - goto ERROR1; - } - } - - if (kind <= 0) { - int ver = lm93_read_byte(client, LM93_REG_VER); - - if ((ver == LM93_MFR_ID) || (ver == LM93_MFR_ID_PROTOTYPE)) { - kind = lm93; - } else { - pr_debug("lm93.o: detect failed, " - "bad version id 0x%02x!\n", ver); - if (kind == 0) - pr_debug("lm93.o: " - "(ignored 'force' parameter)\n"); - goto ERROR1; - } - } - - /* fill in remaining client fields */ - strcpy(client->name, "LM93 chip"); - client->id = lm93_id++; - pr_debug("lm93.o: assigning ID %d to %s at %d,0x%02x\n", client->id, - client->name, i2c_adapter_id(client->adapter), client->addr); - - /* housekeeping */ - data->valid = 0; - data->update = update; - init_MUTEX(&data->update_lock); - - /* tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(client))) - goto ERROR1; - - /* initialize the chip */ - lm93_init_client(client); - - /* register a new directory entry with module sensors */ - if ((data->sysctl_id = i2c_register_entry(client, "lm93", - lm93_dir_table_template, THIS_MODULE)) < 0) { - err = data->sysctl_id; - goto ERROR2; - } - - return 0; - -ERROR2: - i2c_detach_client(client); -ERROR1: - kfree(data); -ERROR0: - return err; -} - -/* This function is called when: - * lm93_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and lm93_driver is still present) */ -static int lm93_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, lm93_detect); -} - -static int lm93_detach_client(struct i2c_client *client) -{ - int err; - struct lm93_data *data = client->data; - - i2c_deregister_entry(data->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk (KERN_ERR "lm93.o: Client deregistration failed; " - "client not detached.\n"); - return err; - } - kfree(data); - return 0; -} - -static struct i2c_driver lm93_driver = { - .name = "LM93 sensor driver", - .id = I2C_DRIVERID_LM93, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm93_attach_adapter, - .detach_client = lm93_detach_client, -}; - -static int __init lm93_init(void) -{ - printk(KERN_INFO "lm93.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&lm93_driver); -} - -static void __exit lm93_exit(void) -{ - i2c_del_driver(&lm93_driver); -} - -MODULE_AUTHOR("Mark M. Hoffman "); -MODULE_DESCRIPTION("LM93 driver"); -MODULE_LICENSE("GPL"); - -module_init(lm93_init); -module_exit(lm93_exit); diff --git a/kernel/chips/lm93.h b/kernel/chips/lm93.h deleted file mode 100644 index c61a4c81..00000000 --- a/kernel/chips/lm93.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - lm93.h - Part of lm_sensors, Linux kernel modules for hardware monitoring - - Author/Maintainer: Mark M. Hoffman - Copyright (c) 2004 Utilitek Systems, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef LM93_H -#define LM93_H - -/* LM93 REGISTER ADDRESSES */ - -/* miscellaneous */ -#define LM93_REG_MFR_ID 0x3e -#define LM93_REG_VER 0x3f -#define LM93_REG_STATUS_CONTROL 0xe2 -#define LM93_REG_CONFIG 0xe3 -#define LM93_REG_SLEEP_CONTROL 0xe4 - -/* alarm values start here */ -#define LM93_REG_HOST_ERROR_1 0x48 - -/* voltage inputs: in1-in16 (nr => 0-15) */ -#define LM93_REG_IN(nr) (0x56 + (nr)) -#define LM93_REG_IN_MIN(nr) (0x90 + (nr) * 2) -#define LM93_REG_IN_MAX(nr) (0x91 + (nr) * 2) - -/* temperature inputs: temp1-temp4 (nr => 0-3) */ -#define LM93_REG_TEMP(nr) (0x50 + (nr)) -#define LM93_REG_TEMP_MIN(nr) (0x78 + (nr) * 2) -#define LM93_REG_TEMP_MAX(nr) (0x79 + (nr) * 2) - -/* temp[1-4]_auto_boost (nr => 0-3) */ -#define LM93_REG_BOOST(nr) (0x80 + (nr)) - -/* #PROCHOT inputs: prochot1-prochot2 (nr => 0-1) */ -#define LM93_REG_PROCHOT_CUR(nr) (0x67 + (nr) * 2) -#define LM93_REG_PROCHOT_AVG(nr) (0x68 + (nr) * 2) -#define LM93_REG_PROCHOT_MAX(nr) (0xb0 + (nr)) - -/* fan tach inputs: fan1-fan4 (nr => 0-3) */ -#define LM93_REG_FAN(nr) (0x6e + (nr) * 2) -#define LM93_REG_FAN_MIN(nr) (0xb4 + (nr) * 2) - -/* pwm outputs: pwm1-pwm2 (nr => 0-1, reg => 0-3) */ -#define LM93_REG_PWM_CTL(nr,reg) (0xc8 + (reg) + (nr) * 4) -#define LM93_PWM_CTL1 0 -#define LM93_PWM_CTL2 1 -#define LM93_PWM_CTL3 2 -#define LM93_PWM_CTL4 3 - -/* GPIO input state */ -#define LM93_REG_GPI 0x6b - -/* vid inputs: vid1-vid2 (nr => 0-1) */ -#define LM93_REG_VID(nr) (0x6c + (nr)) - -/* vccp1 & vccp2: VID relative inputs (nr => 0-1) */ -#define LM93_REG_VCCP_LIMIT_OFF(nr) (0xb2 + (nr)) - -/* temp[1-4]_auto_boost_hyst */ -#define LM93_REG_BOOST_HYST_12 0xc0 -#define LM93_REG_BOOST_HYST_34 0xc1 -#define LM93_REG_BOOST_HYST(nr) (0xc0 + (nr)/2) - -/* temp[1-4]_auto_pwm_[min|hyst] */ -#define LM93_REG_PWM_MIN_HYST_12 0xc3 -#define LM93_REG_PWM_MIN_HYST_34 0xc4 -#define LM93_REG_PWM_MIN_HYST(nr) (0xc3 + (nr)/2) - -/* prochot_override & prochot_interval */ -#define LM93_REG_PROCHOT_OVERRIDE 0xc6 -#define LM93_REG_PROCHOT_INTERVAL 0xc7 - -/* temp[1-4]_auto_base (nr => 0-3) */ -#define LM93_REG_TEMP_BASE(nr) (0xd0 + (nr)) - -/* temp[1-4]_auto_offsets (step => 0-11) */ -#define LM93_REG_TEMP_OFFSET(step) (0xd4 + (step)) - -/* #PROCHOT & #VRDHOT PWM ramp control */ -#define LM93_REG_PWM_RAMP_CTL 0xbf - -/* miscellaneous */ -#define LM93_REG_SFC1 0xbc -#define LM93_REG_SFC2 0xbd -#define LM93_REG_GPI_VID_CTL 0xbe -#define LM93_REG_SF_TACH_TO_PWM 0xe0 - -/* error masks */ -#define LM93_REG_GPI_ERR_MASK 0xec -#define LM93_REG_MISC_ERR_MASK 0xed - -/* LM93 REGISTER VALUES */ -#define LM93_MFR_ID 0x73 -#define LM93_MFR_ID_PROTOTYPE 0x72 - -#endif /* !defined LM93_H */ - diff --git a/kernel/chips/ltc1710.c b/kernel/chips/ltc1710.c deleted file mode 100644 index 80417983..00000000 --- a/kernel/chips/ltc1710.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - ltc1710.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1999 Frodo Looijaard and - Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* A few notes about the LTC1710: - -* The LTC1710 is a dual programmable switch. It can be used to turn - anything on or off anything which consumes less than 300mA of - current and up to 5.5V - -* The LTC1710 is a very, very simple SMBus device with three possible - SMBus addresses (0x58,0x59, or 0x5A). Only SMBus byte writes - (command writes) are supported. - -* Since only writes are supported, READS DON'T WORK! The device - plays dead in the event of a read, so this makes detection a - bit tricky. - -* BTW- I can safely say that this driver has been tested under - every possible case, so there should be no bugs. :') - - --Phil - -*/ - - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x58, 0x5a, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(ltc1710); - -/* The LTC1710 registers */ - -/* (No registers. [Wow! This thing is SIMPLE!] ) */ - -/* Initial values */ -#define LTC1710_INIT 0 /* Both off */ - -/* Each client has this additional data */ -struct ltc1710_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 status; /* Register values */ -}; - -static int ltc1710_attach_adapter(struct i2c_adapter *adapter); -static int ltc1710_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int ltc1710_detach_client(struct i2c_client *client); - -static void ltc1710_switch1(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ltc1710_switch2(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void ltc1710_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver ltc1710_driver = { - .name = "LTC1710 sensor chip driver", - .id = I2C_DRIVERID_LTC1710, - .flags = I2C_DF_NOTIFY, - .attach_adapter = ltc1710_attach_adapter, - .detach_client = ltc1710_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define LTC1710_SYSCTL_SWITCH_1 1000 -#define LTC1710_SYSCTL_SWITCH_2 1001 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected LTC1710. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table ltc1710_dir_table_template[] = { - {LTC1710_SYSCTL_SWITCH_1, "switch1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, <c1710_switch1}, - {LTC1710_SYSCTL_SWITCH_2, "switch2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, <c1710_switch2}, - {0} -}; - -static int ltc1710_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, ltc1710_detect); -} - -/* This function is called by i2c_detect */ -int ltc1710_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct ltc1710_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("ltc1710.o: ltc1710_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access ltc1710_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct ltc1710_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = <c1710_driver; - new_client->flags = 0; - - /* Now, we would do the remaining detection. But the LTC1710 is plainly - impossible to detect! Stupid chip. */ - - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = ltc1710; - - if (kind == ltc1710) { - type_name = "ltc1710"; - client_name = "LTC1710 chip"; - } else { -#ifdef DEBUG - printk("ltc1710.o: Internal error: unknown kind (%d)?!?", - kind); -#endif - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - ltc1710_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - - -static int ltc1710_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct ltc1710_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("ltc1710.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; - -} - -static void ltc1710_update_client(struct i2c_client *client) -{ - struct ltc1710_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting ltc1710 update\n"); -#endif - - /* data->status = i2c_smbus_read_byte(client); - Unfortunately, reads always fail! */ - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void ltc1710_switch1(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ltc1710_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ltc1710_update_client(client); - results[0] = data->status & 1; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->status = (data->status & 2) | results[0]; - i2c_smbus_write_byte(client, data->status); - } - } -} - -void ltc1710_switch2(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct ltc1710_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ltc1710_update_client(client); - results[0] = (data->status & 2) >> 1; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->status = - (data->status & 1) | (results[0] << 1); - i2c_smbus_write_byte(client, data->status); - } - } -} - -static int __init sm_ltc1710_init(void) -{ - printk("ltc1710.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(<c1710_driver); -} - -static void __exit sm_ltc1710_exit(void) -{ - i2c_del_driver(<c1710_driver); -} - - - -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("LTC1710 driver"); - -module_init(sm_ltc1710_init); -module_exit(sm_ltc1710_exit); diff --git a/kernel/chips/matorb.c b/kernel/chips/matorb.c deleted file mode 100644 index 1e6de8a7..00000000 --- a/kernel/chips/matorb.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - matorb.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - and Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - - -#define DEBUG 1 - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2E, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(matorb); - -/* Many MATORB constants specified below */ - - -/* Each client has this additional data */ -struct matorb_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - -}; - -static int matorb_attach_adapter(struct i2c_adapter *adapter); -static int matorb_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void matorb_init_client(struct i2c_client *client); -static int matorb_detach_client(struct i2c_client *client); - -static int matorb_write_value(struct i2c_client *client, u8 reg, - u16 value); -static void matorb_disp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void matorb_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver matorb_driver = { - .name = "Matrix Orbital LCD driver", - .id = I2C_DRIVERID_MATORB, - .flags = I2C_DF_NOTIFY, - .attach_adapter = matorb_attach_adapter, - .detach_client = matorb_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define MATORB_SYSCTL_DISP 1000 -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected MATORB. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table matorb_dir_table_template[] = { - {MATORB_SYSCTL_DISP, "disp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &matorb_disp}, - {0} -}; - -static int matorb_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, matorb_detect); -} - -/* This function is called by i2c_detect */ -int matorb_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i, cur; - struct i2c_client *new_client; - struct matorb_data *data; - int err = 0; - const char *type_name = "matorb"; - const char *client_name = "matorb"; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("matorb.o: matorb_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE | - I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) - goto ERROR0; - - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access matorb_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct matorb_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &matorb_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. It is lousy. */ - cur = i2c_smbus_write_byte_data(new_client, 0x0FE, 0x58); /* clear screen */ - - printk("matorb.o: debug detect 0x%X\n", cur); - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - matorb_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - matorb_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - kfree(data); - ERROR0: - return err; -} - -static int matorb_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct matorb_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("matorb.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - - -#if 0 -/* All registers are word-sized, except for the configuration register. - MATORB uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int matorb_read_value(struct i2c_client *client, u8 reg) -{ - return -1; /* Doesn't support reads */ -} -#endif - -/* All registers are word-sized, except for the configuration register. - MATORB uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int matorb_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (reg == 0) { - return i2c_smbus_write_byte(client, value); - } else { - return i2c_smbus_write_byte_data(client, reg, value); - } -} - -static void matorb_init_client(struct i2c_client *client) -{ - /* Initialize the MATORB chip */ -} - -static void matorb_update_client(struct i2c_client *client) -{ - struct matorb_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting matorb update\n"); -#endif - -/* nothing yet */ - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void matorb_disp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int i; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - matorb_update_client(client); - results[0] = 0; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - for (i = 1; i <= *nrels_mag; i++) { - matorb_write_value(client, 0, results[i - 1]); - } - } -} - -static int __init sm_matorb_init(void) -{ - printk("matorb.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&matorb_driver); -} - -static void __exit sm_matorb_exit(void) -{ - i2c_del_driver(&matorb_driver); -} - - - -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("MATORB driver"); - -module_init(sm_matorb_init); -module_exit(sm_matorb_exit); diff --git a/kernel/chips/max1619.c b/kernel/chips/max1619.c deleted file mode 100644 index 86943983..00000000 --- a/kernel/chips/max1619.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - * max1619.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2004 Alexey Fisher - * Jean Delvare - * - * Copied from lm90.c: - * Copyright (C) 2003-2004 Jean Delvare - * - * The MAX1619 is a sensor chip made by Maxim. It reports up to two - * temperatures (its own plus up to one external one). - * Complete datasheet can be obtained from Maxim's website at: - * http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include "version.h" - -/* - * Addresses to scan - */ - -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = {0x18, 0x1a, 0x29, 0x2b, - 0x4c, 0x4e, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(max1619); - -/* - * The max1619 registers - */ - -#define MAX1619_REG_R_CONFIG 0x03 -#define MAX1619_REG_W_CONFIG 0x09 -#define MAX1619_REG_R_CONVRATE 0x04 -#define MAX1619_REG_W_CONVRATE 0x0A -#define MAX1619_REG_R_STATUS 0x02 -#define MAX1619_REG_R_LOCAL_TEMP 0x00 -#define MAX1619_REG_R_REMOTE_TEMP 0x01 -#define MAX1619_REG_R_REMOTE_THIGH 0x07 -#define MAX1619_REG_W_REMOTE_THIGH 0x0d -#define MAX1619_REG_R_REMOTE_TLOW 0x08 -#define MAX1619_REG_W_REMOTE_TLOW 0x0E -#define MAX1619_REG_R_REMOTE_TMAX 0x10 -#define MAX1619_REG_W_REMOTE_TMAX 0x12 -#define MAX1619_REG_R_REMOTE_THYST 0x11 -#define MAX1619_REG_W_REMOTE_THYST 0x13 -#define MAX1619_REG_R_MAN_ID 0xFE -#define MAX1619_REG_R_CHIP_ID 0xFF - -/* - * Conversions and various macros - */ - -#define TEMP_FROM_REG(val) ((val) & 0x80 ? (val)-0x100 : (val)) -#define TEMP_TO_REG(val) ((val) < 0 ? (val)+0x100 : (val)) - -/* - * Functions declaration - */ - -static int max1619_attach_adapter(struct i2c_adapter *adapter); -static int max1619_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void max1619_init_client(struct i2c_client *client); -static int max1619_detach_client(struct i2c_client *client); -static void max1619_local_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void max1619_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void max1619_remote_crit(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void max1619_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver max1619_driver = { - .name = "MAX1619 sensor driver", - .flags = I2C_DF_NOTIFY, - .attach_adapter = max1619_attach_adapter, - .detach_client = max1619_detach_client -}; - -/* - * Client data (each client gets its own) - */ - -struct max1619_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* register values */ - u8 local_temp; - u8 remote_temp, remote_high, remote_low; - u8 remote_hyst, remote_max; - u8 alarms; -}; - -/* - * Proc entries - * These files are created for each detected max1619. - */ - -/* -- SENSORS SYSCTL START -- */ - -#define MAX1619_SYSCTL_LOCAL_TEMP 1200 -#define MAX1619_SYSCTL_REMOTE_TEMP 1201 -#define MAX1619_SYSCTL_REMOTE_CRIT 1202 -#define MAX1619_SYSCTL_ALARMS 1203 - -#define MAX1619_ALARM_REMOTE_THIGH 0x10 -#define MAX1619_ALARM_REMOTE_TLOW 0x08 -#define MAX1619_ALARM_REMOTE_OPEN 0x04 -#define MAX1619_ALARM_REMOTE_OVERT 0x02 - -/* -- SENSORS SYSCTL END -- */ - - -static ctl_table max1619_dir_table_template[] = -{ - {MAX1619_SYSCTL_LOCAL_TEMP, "temp1", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_local_temp}, - {MAX1619_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_remote_temp}, - {MAX1619_SYSCTL_REMOTE_CRIT,"temp2_crit", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_remote_crit}, - {MAX1619_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_alarms}, - {0} -}; - -/* - * Real code - */ - -static int max1619_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, max1619_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int max1619_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - struct i2c_client *new_client; - struct max1619_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk(KERN_DEBUG "max1619.o: Called for an ISA bus " - "adapter, aborting.\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { -#ifdef DEBUG - printk(KERN_DEBUG "max1619.o: I2C bus doesn't support " - "byte read mode, skipping.\n"); -#endif - return 0; - } - - if (!(data = kmalloc(sizeof(struct max1619_data), GFP_KERNEL))) { - printk(KERN_ERR "max1619.o: Out of memory in " - "max1619_detect (new_client).\n"); - return -ENOMEM; - } - - /* - * The common I2C client data is placed right before the - * MAX1619-specific data. The MAX1619-specific data is pointed to - * by the data field from the I2C client da1ta. - */ - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &max1619_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip. A zero kind means that - * the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - */ - - if (kind < 0) { - u8 reg_config, reg_convrate, reg_status; - - reg_config = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_CONFIG); - reg_convrate = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_CONVRATE); - reg_status = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_STATUS); - - if ((reg_config & 0x03) != 0x00 - || reg_convrate > 0x07 - || (reg_status & 0x61) != 0x00) { -#ifdef DEBUG - printk(KERN_DEBUG "max1619.o: Detection failed at " - "0x%02x.\n", address); -#endif - goto ERROR1; - } - } - - if (kind <= 0) { - u8 man_id, chip_id; - - man_id = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - MAX1619_REG_R_CHIP_ID); - - if ((man_id == 0x4D) && (chip_id == 0x04)) { - kind = max1619; - } - } - - if (kind <= 0) { - printk(KERN_INFO "max1619.o: Unsupported chip.\n"); - goto ERROR1; - } - - if (kind == max1619) { - type_name = "max1619"; - client_name = "MAX1619 chip"; - } else { - printk(KERN_ERR "max1619.o: Unknown kind %d.\n", kind); - goto ERROR1; - } - - /* - * OK, we got a valid chip so we can fill in the remaining client - * fields. - */ - - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* - * Tell the I2C layer a new client has arrived. - */ - - if ((err = i2c_attach_client(new_client))) { - printk(KERN_ERR "max1619.o: Failed attaching client.\n"); - goto ERROR1; - } - - /* - * Register a new directory entry. - */ - - if ((err = i2c_register_entry(new_client, type_name, - max1619_dir_table_template, THIS_MODULE)) < 0) { - printk(KERN_ERR "max1619.o: Failed registering directory " - "entry.\n"); - goto ERROR2; - } - data->sysctl_id = err; - - /* - * Initialize the MAX1619 chip. - */ - - max1619_init_client(new_client); - return 0; - -ERROR2: - i2c_detach_client(new_client); -ERROR1: - kfree(data); - return err; -} - -static void max1619_init_client(struct i2c_client *client) -{ - u8 config; - - /* - * Start the conversions. - */ - - /* Set conversion rate to 2 Hz */ - i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONVRATE, 5); - - /* Start monitoring */ - config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG); - if (config & 0x40) - i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONFIG, - config & 0xBF); -} - - -static int max1619_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct max1619_data *) - (client->data))->sysctl_id); - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR "max1619.o: Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(client->data); - return 0; -} - -static void max1619_update_client(struct i2c_client *client) -{ - struct max1619_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ * 2) || - (jiffies < data->last_updated) || !data->valid) { -#ifdef DEBUG - printk(KERN_DEBUG "max1619.o: Updating data.\n"); -#endif - - data->local_temp = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_LOCAL_TEMP); - data->remote_temp = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_TEMP); - data->remote_high = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_THIGH); - data->remote_low = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_TLOW); - data->remote_max = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_TMAX); - data->remote_hyst = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_REMOTE_THYST); - data->alarms = i2c_smbus_read_byte_data(client, - MAX1619_REG_R_STATUS); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -static void max1619_local_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct max1619_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - max1619_update_client(client); - results[0] = TEMP_FROM_REG(data->local_temp); - *nrels_mag = 1; - } - -} - -static void max1619_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct max1619_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - max1619_update_client(client); - results[0] = TEMP_FROM_REG(data->remote_high); - results[1] = TEMP_FROM_REG(data->remote_low); - results[2] = TEMP_FROM_REG(data->remote_temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->remote_high = TEMP_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, - MAX1619_REG_W_REMOTE_THIGH, data->remote_high); - } - if (*nrels_mag >= 2) { - data->remote_low = TEMP_TO_REG(results[1]); - i2c_smbus_write_byte_data(client, - MAX1619_REG_W_REMOTE_TLOW, data->remote_low); - - } - } -} - -static void max1619_remote_crit(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct max1619_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - max1619_update_client(client); - results[0] = TEMP_FROM_REG(data->remote_max); - results[1] = TEMP_FROM_REG(data->remote_hyst); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->remote_max = TEMP_TO_REG(results[0]); - i2c_smbus_write_byte_data(client, - MAX1619_REG_W_REMOTE_TMAX, data->remote_max); - } - if (*nrels_mag >= 2) { - data->remote_hyst = TEMP_TO_REG(results[1]); - i2c_smbus_write_byte_data(client, - MAX1619_REG_W_REMOTE_THYST, data->remote_hyst); - } - } -} - -static void max1619_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct max1619_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; /* magnitude */ - else if (operation == SENSORS_PROC_REAL_READ) { - max1619_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - - -static int __init sm_max1619_init(void) -{ - printk(KERN_INFO "max1619.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&max1619_driver); -} - -static void __exit sm_max1619_exit(void) -{ - i2c_del_driver(&max1619_driver); -} - -MODULE_AUTHOR("Alexey Fisher "); -MODULE_DESCRIPTION("MAX1619 sensor driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_max1619_init); -module_exit(sm_max1619_exit); diff --git a/kernel/chips/max6650.c b/kernel/chips/max6650.c deleted file mode 100644 index c7975a90..00000000 --- a/kernel/chips/max6650.c +++ /dev/null @@ -1,537 +0,0 @@ -/* - * max6650.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring. - * - * Author: John Morris - * - * Copyright (c) 2003 Spirent Communications - * - * This module has only been tested with the MAX6651 chip. It should - * work with the MAX6650 also, though with reduced functionality. It - * does not yet distinguish max6650 and max6651 chips. - * - * Tha datasheet was last seen at: - * - * http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include "version.h" - -#ifndef I2C_DRIVERID_MAX6650 -#define I2C_DRIVERID_MAX6650 1044 -#endif - -/* - * Addresses to scan. There are four disjoint possibilities, by pin config. - */ - -static unsigned short normal_i2c[] = {0x1b, 0x1f, 0x48, 0x4b, SENSORS_I2C_END}; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(max6650); - -/* - * MAX 6650/6651 registers - */ - -#define MAX6650_REG_SPEED 0x00 -#define MAX6650_REG_CONFIG 0x02 -#define MAX6650_REG_GPIO_DEF 0x04 -#define MAX6650_REG_DAC 0x06 -#define MAX6650_REG_ALARM_EN 0x08 -#define MAX6650_REG_ALARM 0x0A -#define MAX6650_REG_TACH0 0x0C -#define MAX6650_REG_TACH1 0x0E -#define MAX6650_REG_TACH2 0x10 -#define MAX6650_REG_TACH3 0x12 -#define MAX6650_REG_GPIO_STAT 0x14 -#define MAX6650_REG_COUNT 0x16 - -/* - * Config register bits - */ - -#define MAX6650_CFG_MODE_MASK 0x30 -#define MAX6650_CFG_MODE_ON 0x00 -#define MAX6650_CFG_MODE_OFF 0x10 -#define MAX6650_CFG_MODE_CLOSED_LOOP 0x20 -#define MAX6650_CFG_MODE_OPEN_LOOP 0x30 - -static const u8 tach_reg[] = -{ - MAX6650_REG_TACH0, MAX6650_REG_TACH1, - MAX6650_REG_TACH2, MAX6650_REG_TACH3 -}; - -#define MAX6650_INT_CLK 254000 /* Default clock speed - 254 kHz */ - -/* - * Functions declaration - */ - -static void max6650_fan (struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results); -static void max6650_speed (struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results); -static void max6650_xdump (struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results); -static int max6650_detect(struct i2c_adapter *adapter, int address, unsigned - short flags, int kind); -static int max6650_attach_adapter(struct i2c_adapter *adapter); -static int max6650_detach_client(struct i2c_client *client); -static void max6650_init_client(struct i2c_client *client); -static int max6650_read(struct i2c_client *client, u8 reg); - -/* - * Driver data (common to all clients) - */ - - -static struct i2c_driver max6650_driver = { - .name = "MAX6650/1 sensor driver", - .id = I2C_DRIVERID_MAX6650, - .flags = I2C_DF_NOTIFY, - .attach_adapter = max6650_attach_adapter, - .detach_client = max6650_detach_client -}; - -/* - * Client data (each client gets its own) - */ - -struct max6650_data -{ - struct i2c_client client; - int sysctl_id; - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* register values */ - - u8 speed; - u8 config; - u8 tach[4]; - u8 count; -}; - -/* - * Proc entries - * These files are created for each detected max6650. - */ - -/* -- SENSORS SYSCTL START -- */ - -#define MAX6650_SYSCTL_FAN1 1101 -#define MAX6650_SYSCTL_FAN2 1102 -#define MAX6650_SYSCTL_FAN3 1103 -#define MAX6650_SYSCTL_FAN4 1104 -#define MAX6650_SYSCTL_SPEED 1105 -#define MAX6650_SYSCTL_XDUMP 1106 - - -/* -- SENSORS SYSCTL END -- */ - - -static ctl_table max6650_dir_table_template[] = -{ - {MAX6650_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max6650_fan}, - {MAX6650_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max6650_fan}, - {MAX6650_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max6650_fan}, - {MAX6650_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max6650_fan}, - {MAX6650_SYSCTL_SPEED, "speed", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max6650_speed}, - {MAX6650_SYSCTL_XDUMP, "xdump", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &max6650_xdump}, - {0} -}; - -/* - * Real code - */ - -static int max6650_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, max6650_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ - -static int max6650_detect(struct i2c_adapter *adapter, int address, unsigned - short flags, int kind) -{ - struct i2c_client *new_client; - struct max6650_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk("max6650.o: Called for an ISA bus adapter, aborting.\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { -#ifdef DEBUG - printk("max6650.o: I2C bus doesn't support byte read mode, skipping.\n"); -#endif - return 0; - } - - if (!(data = kmalloc(sizeof(struct max6650_data), GFP_KERNEL))) { - printk("max6650.o: Out of memory in max6650_detect (new_client).\n"); - return -ENOMEM; - } - - /* - * The common I2C client data is placed right before the - * max6650-specific data. The max6650-specific data is pointed to by the - * data field from the I2C client data. - */ - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &max6650_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip (actually there is only - * one possible kind of chip for now, max6650). A zero kind means that - * the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - * - * Currently I can find no way to distinguish between a MAX6650 and - * a MAX6651. This driver has only been tried on the latter. - */ - - if (kind < 0) { /* detection */ - if ( - (max6650_read(new_client, MAX6650_REG_CONFIG) & 0xC0) || - (max6650_read(new_client, MAX6650_REG_GPIO_STAT) & 0xE0) || - (max6650_read(new_client, MAX6650_REG_ALARM_EN) & 0xE0) || - (max6650_read(new_client, MAX6650_REG_ALARM) & 0xE0) || - (max6650_read(new_client, MAX6650_REG_COUNT) & 0xFC) - ) - { -#ifdef DEBUG - printk("max6650.o: max6650 detection failed at 0x%02x.\n", - address); -#endif - goto ERROR1; - } - } - - if (kind <= 0) { /* identification */ - kind = max6650; - } - - if (kind <= 0) { /* identification failed */ - printk("max6650.o: Unsupported chip.\n"); - goto ERROR1; - } - - if (kind == max6650) { - type_name = "max6650"; - client_name = "max6650 chip"; - } else { - printk("max6650.o: Unknown kind %d.\n", kind); - goto ERROR1; - } - - /* - * OK, we got a valid chip so we can fill in the remaining client - * fields. - */ - - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* - * Tell the I2C layer a new client has arrived. - */ - - if ((err = i2c_attach_client(new_client))) { -#ifdef DEBUG - printk("max6650.o: Failed attaching client.\n"); -#endif - goto ERROR1; - } - - /* - * Register a new directory entry. - */ - if ((err = i2c_register_entry(new_client, type_name, - max6650_dir_table_template, - THIS_MODULE)) < 0) { -#ifdef DEBUG - printk("max6650.o: Failed registering directory entry.\n"); -#endif - goto ERROR2; - } - data->sysctl_id = err; - - /* - * Initialize the max6650 chip - */ - max6650_init_client(new_client); - return 0; - -ERROR2: - i2c_detach_client(new_client); -ERROR1: - kfree(data); - return err; -} - -static void max6650_init_client(struct i2c_client *client) -{ - /* Nothing to do here - assume the BIOS has initialized the chip */ -} - -static int max6650_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct max6650_data *) (client->data))->sysctl_id); - if ((err = i2c_detach_client(client))) { - printk("max6650.o: Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(client->data); - return 0; -} - -static int max6650_read(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int max6650_write(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static void max6650_update_client(struct i2c_client *client) -{ - int i; - struct max6650_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ) || - (jiffies < data->last_updated) || !data->valid) { -#ifdef DEBUG - printk("max6650.o: Updating max6650 data.\n"); -#endif - data->speed = max6650_read (client, MAX6650_REG_SPEED); - data->config = max6650_read (client, MAX6650_REG_CONFIG); - for (i = 0; i < 4; i++) { - data->tach[i] = max6650_read(client, tach_reg[i]); - } - data->count = max6650_read (client, MAX6650_REG_COUNT); - data->last_updated = jiffies; - data->valid = 1; - } - up(&data->update_lock); -} - -static void max6650_fan (struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results) -{ - int index = ctl_name - MAX6650_SYSCTL_FAN1; - struct max6650_data *data = client->data; - int tcount; /* Tachometer count time, 0.25 second units */ - - if (operation == SENSORS_PROC_REAL_INFO) { - *nrels_mag = 0; - } else if (operation == SENSORS_PROC_REAL_READ) { - max6650_update_client(client); - - /* - * Calculation details: - * - * Each tachometer counts over an interval given by the "count" - * register (0.25, 0.5, 1 or 2 seconds). This module assumes - * that the fans produce two pulses per revolution (this seems - * to be the most common). - */ - - tcount = 1 << data->count; /* 0.25 second units */ - results[0] = (data->tach[index] * 240) / tcount; /* counts per min */ - results[0] /= 2; /* Assume two counts per rev */ - *nrels_mag = 1; - } -} - -/* - * Set the fan speed to the specified RPM (or read back the RPM setting). - * - * The MAX6650/1 will automatically control fan speed when in closed loop - * mode. - * - * Assumptions: - * - * 1) The MAX6650/1 is running from its internal 254kHz clock (perhaps - * this should be made a module parameter). - * - * 2) The prescaler (low three bits of the config register) has already - * been set to an appropriate value. - * - * The relevant equations are given on pages 21 and 22 of the datasheet. - * - * From the datasheet, the relevant equation when in regulation is: - * - * [fCLK / (128 x (KTACH + 1))] = 2 x FanSpeed / KSCALE - * - * where: - * - * fCLK is the oscillator frequency (either the 254kHz internal - * oscillator or the externally applied clock) - * - * KTACH is the value in the speed register - * - * FanSpeed is the speed of the fan in rps - * - * KSCALE is the prescaler value (1, 2, 4, 8, or 16) - * - * When reading, we need to solve for FanSpeed. When writing, we need to - * solve for KTACH. - * - * Note: this tachometer is completely separate from the tachometers - * used to measure the fan speeds. Only one fan's speed (fan1) is - * controlled. - */ - -static void max6650_speed (struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results) -{ - struct max6650_data *data = client->data; - int kscale, ktach, fclk, rpm; - - if (operation == SENSORS_PROC_REAL_INFO) { - *nrels_mag = 0; - } else if (operation == SENSORS_PROC_REAL_READ) { - /* - * Use the datasheet equation: - * - * FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)] - * - * then multiply by 60 to give rpm. - */ - - max6650_update_client(client); - - kscale = 1 << (data->config & 7); - ktach = data->speed; - fclk = MAX6650_INT_CLK; - rpm = 60 * kscale * fclk / (256 * (ktach + 1)); - - results[0] = rpm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE && *nrels_mag >= 1) { - /* - * Divide the required speed by 60 to get from rpm to rps, then - * use the datasheet equation: - * - * KTACH = [(fCLK x KSCALE) / (256 x FanSpeed)] - 1 - */ - - max6650_update_client(client); - - rpm = results[0]; - kscale = 1 << (data->config & 7); - fclk = MAX6650_INT_CLK; - ktach = ((fclk * kscale) / (256 * rpm / 60)) - 1; - - data->speed = ktach; - data->config = (data->config & ~MAX6650_CFG_MODE_MASK) | - MAX6650_CFG_MODE_CLOSED_LOOP; - max6650_write (client, MAX6650_REG_CONFIG, data->config); - max6650_write (client, MAX6650_REG_SPEED, data->speed); - } -} - -/* - * Debug - dump all registers except the tach counts. - */ - -static void max6650_xdump (struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results) -{ - if (operation == SENSORS_PROC_REAL_INFO) { - *nrels_mag = 0; - } else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = max6650_read (client, MAX6650_REG_SPEED); - results[1] = max6650_read (client, MAX6650_REG_CONFIG); - results[2] = max6650_read (client, MAX6650_REG_GPIO_DEF); - results[3] = max6650_read (client, MAX6650_REG_DAC); - results[4] = max6650_read (client, MAX6650_REG_ALARM_EN); - results[5] = max6650_read (client, MAX6650_REG_ALARM); - results[6] = max6650_read (client, MAX6650_REG_GPIO_STAT); - results[7] = max6650_read (client, MAX6650_REG_COUNT); - *nrels_mag = 8; - } -} - -static int __init sm_max6650_init(void) -{ - printk(KERN_INFO "max6650.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&max6650_driver); -} - -static void __exit sm_max6650_exit(void) -{ - i2c_del_driver(&max6650_driver); -} - -MODULE_AUTHOR("john.morris@spirentcom.com"); -MODULE_DESCRIPTION("max6650 sensor driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_max6650_init); -module_exit(sm_max6650_exit); diff --git a/kernel/chips/maxilife.c b/kernel/chips/maxilife.c deleted file mode 100644 index 7eab4be5..00000000 --- a/kernel/chips/maxilife.c +++ /dev/null @@ -1,1379 +0,0 @@ -/* - maxilife.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1999-2000 Fons Rademakers - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* The is the driver for the HP MaxiLife Health monitoring system - as used in the line of HP Kayak Workstation PC's. - - The driver supports the following MaxiLife firmware versions: - - 0) HP KAYAK XU/XAs (Dual Pentium II Slot 1, Deschutes/Klamath) - 1) HP KAYAK XU (Dual Xeon [Slot 2] 400/450 Mhz) - 2) HP KAYAK XA (Pentium II Slot 1, monoprocessor) - - Currently firmware auto detection is not implemented. To use the - driver load it with the correct option for you Kayak. For example: - - insmod maxilife.o maxi_version=0 | 1 | 2 - - maxi_version=0 is the default - - This version of MaxiLife is called MaxiLife'98 and has been - succeeded by MaxiLife'99, see below. - - The new version of the driver also supports MaxiLife NBA (New BIOS - Architecture). This new MaxiLife controller provides a much cleaner - machine independent abstraction layer to the MaxiLife controller. - Instead of accessing directly registers (different for each revision) - one now accesses the sensors via unique mailbox tokens that do not - change between revisions. Also the quantities are already in physical - units (degrees, rpms, voltages, etc.) and don't need special conversion - formulas. This new MaxiLife is available on the new 2000 machines, - like the Kayak XU800 and XM600. This hardware is also autodetected. -*/ - -static const char *version_str = "2.00 29/2/2000 Fons Rademakers"; - - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -#undef AUTODETECT /* try to autodetect MaxiLife version */ -/*#define AUTODETECT*/ -#define NOWRITE /* don't allow writing to MaxiLife registers */ - -#ifdef AUTODETECT -#include -#include -#endif - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x10, 0x14, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(maxilife); - -/* Macro definitions */ -#define LOW(MyWord) ((u8) (MyWord)) -#define HIGH(MyWord) ((u8) (((u16)(MyWord) >> 8) & 0xFF)) - -/*----------------- MaxiLife'98 registers and conversion formulas ------------*/ -#define MAXI_REG_TEMP(nr) (0x60 + (nr)) - -#define MAXI_REG_FAN(nr) (0x65 + (nr)) -#define MAXI_REG_FAN_MIN(nr) ((nr)==0 ? 0xb3 : (nr)==1 ? 0xb3 : 0xab) -#define MAXI_REG_FAN_MINAS(nr) ((nr)==0 ? 0xb3 : (nr)==1 ? 0xab : 0xb3) -#define MAXI_REG_FAN_SPEED(nr) ((nr)==0 ? 0xe4 : (nr)==1 ? 0xe5 : 0xe9) - -#define MAXI_REG_PLL 0xb9 -#define MAXI_REG_PLL_MIN 0xba -#define MAXI_REG_PLL_MAX 0xbb - -#define MAXI_REG_VID(nr) ((nr)==0 ? 0xd1 : (nr)==1 ? 0xd9 : \ - (nr)==2 ? 0xd4 : 0xc5) -#define MAXI_REG_VID_MIN(nr) MAXI_REG_VID(nr)+1 -#define MAXI_REG_VID_MAX(nr) MAXI_REG_VID(nr)+2 - -#define MAXI_REG_DIAG_RT1 0x2c -#define MAXI_REG_DIAG_RT2 0x2d - -#define MAXI_REG_BIOS_CTRL 0x2a - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - - /* 0xfe: fan off, 0xff: stopped (alarm) */ - /* 19531 / val * 60 == 1171860 / val */ -#define FAN_FROM_REG(val) ((val)==0xfe ? 0 : (val)==0xff ? -1 : \ - (val)==0x00 ? -1 : (1171860 / (val))) - -static inline u8 FAN_TO_REG(long rpm) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1171860 + rpm / 2) / (rpm), 1, 254); -} - -#define TEMP_FROM_REG(val) ((val) * 5) -#define TEMP_TO_REG(val) (SENSORS_LIMIT((val+2) / 5),0,0xff) -#define PLL_FROM_REG(val) (((val) * 1000) / 32) -#define PLL_TO_REG(val) (SENSORS_LIMIT((((val) * 32 + 500) / 1000),\ - 0,0xff)) -#define VID_FROM_REG(val) ((val) ? (((val) * 27390) / 256) + 3208 : 0) -#define VID_TO_REG(val) (SENSORS_LIMIT((((val) - 3208) * 256) / 27390, \ - 0,255)) -#define ALARMS_FROM_REG(val) (val) - -/*----------------- MaxiLife'99 mailbox and token definitions ----------------*/ -/* MaxiLife mailbox data register map */ -#define MAXI_REG_MBX_STATUS 0x5a -#define MAXI_REG_MBX_CMD 0x5b -#define MAXI_REG_MBX_TOKEN_H 0x5c -#define MAXI_REG_MBX_TOKEN_L 0x5d -#define MAXI_REG_MBX_DATA 0x60 - -/* Mailbox status register definition */ -#define MAXI_STAT_IDLE 0xff -#define MAXI_STAT_OK 0x00 -#define MAXI_STAT_BUSY 0x0b -/* other values not used */ - -/* Mailbox command register opcodes */ -#define MAXI_CMD_READ 0x02 -#define MAXI_CMD_WRITE 0x03 -/* other values not used */ - -/* MaxiLife NBA Hardware monitoring tokens */ - -/* Alarm tokens (0x1xxx) */ -#define MAXI_TOK_ALARM(nr) (0x1000 + (nr)) -#define MAXI_TOK_ALARM_EVENT 0x1000 -#define MAXI_TOK_ALARM_FAN 0x1001 -#define MAXI_TOK_ALARM_TEMP 0x1002 -#define MAXI_TOK_ALARM_VID 0x1003 /* voltages */ -#define MAXI_TOK_ALARM_AVID 0x1004 /* additional voltages */ -#define MAXI_TOK_ALARM_PWR 0x1101 /* power supply glitch */ - -/* Fan status tokens (0x20xx) */ -#define MAXI_TOK_FAN(nr) (0x2000 + (nr)) -#define MAXI_TOK_FAN_CPU 0x2000 -#define MAXI_TOK_FAN_PCI 0x2001 -#define MAXI_TOK_FAN_HDD 0x2002 /* hard disk bay fan */ -#define MAXI_TOK_FAN_SINK 0x2003 /* heatsink */ - -/* Temperature status tokens (0x21xx) */ -#define MAXI_TOK_TEMP(nr) (0x2100 + (nr)) -#define MAXI_TOK_TEMP_CPU1 0x2100 -#define MAXI_TOK_TEMP_CPU2 0x2101 -#define MAXI_TOK_TEMP_PCI 0x2102 /* PCI/ambient temp */ -#define MAXI_TOK_TEMP_HDD 0x2103 /* hard disk bay temp */ -#define MAXI_TOK_TEMP_MEM 0x2104 /* mother board temp */ -#define MAXI_TOK_TEMP_CPU 0x2105 /* CPU reference temp */ - -/* Voltage status tokens (0x22xx) */ -#define MAXI_TOK_VID(nr) (0x2200 + (nr)) -#define MAXI_TOK_VID_12 0x2200 /* +12 volt */ -#define MAXI_TOK_VID_CPU1 0x2201 /* cpu 1 voltage */ -#define MAXI_TOK_VID_CPU2 0x2202 /* cpu 2 voltage */ -#define MAXI_TOK_VID_L2 0x2203 /* level 2 cache voltage */ -#define MAXI_TOK_VID_M12 0x2204 /* -12 volt */ - -/* Additive voltage status tokens (0x23xx) */ -#define MAXI_TOK_AVID(nr) (0x2300 + (nr)) -#define MAXI_TOK_AVID_15 0x2300 /* 1.5 volt */ -#define MAXI_TOK_AVID_18 0x2301 /* 1.8 volt */ -#define MAXI_TOK_AVID_25 0x2302 /* 2.5 volt */ -#define MAXI_TOK_AVID_33 0x2303 /* 3.3 volt */ -#define MAXI_TOK_AVID_5 0x2304 /* 5 volt */ -#define MAXI_TOK_AVID_M5 0x2305 /* -5 volt */ -#define MAXI_TOK_AVID_BAT 0x2306 /* battery voltage */ - -/* Threshold tokens (0x3xxx) */ -#define MAXI_TOK_MIN(token) ((token) + 0x1000) -#define MAXI_TOK_MAX(token) ((token) + 0x1800) - -/* LCD Panel (0x4xxx) */ -#define MAXI_TOK_LCD(nr) (0x4000 + (nr)) -#define MAXI_TOK_LCD_LINE1 0x4000 -#define MAXI_TOK_LCD_LINE2 0x4001 -#define MAXI_TOK_LCD_LINE3 0x4002 -#define MAXI_TOK_LCD_LINE4 0x4003 - - /* 0xfe: fan off, 0xff: stopped (alarm) */ - /* or not available */ -#define FAN99_FROM_REG(val) ((val)==0xfe ? 0 : (val)==0xff ? -1 : ((val)*39)) - - /* when no CPU2 temp is 127 (0x7f) */ -#define TEMP99_FROM_REG(val) ((val)==0x7f ? -1 : (val)==0xff ? -1 : (val)) - -#define VID99_FROM_REG(nr,val) ((val)==0xff ? 0 : \ - (nr)==1 ? ((val) * 608) : \ - (nr)==2 ? ((val) * 160) : \ - (nr)==3 ? ((val) * 160) : \ - (nr)==4 ? (val) /* no formula spcified */ : \ - (nr)==5 ? ((val) * 823 - 149140) : 0) - - -/* The following product codenames apply: - Cristal/Geronimo: HP KAYAK XU/XAs - (Dual Pentium II Slot 1, Deschutes/Klamath) - Cognac: HP KAYAK XU (Dual Xeon [Slot 2] 400/450 Mhz) - Ashaki: HP KAYAK XA (Pentium II Slot 1, monoprocessor) - NBA: New BIOS Architecture, Kayak XU800, XM600, ... */ - -enum maxi_type { cristal, cognac, ashaki, nba }; -enum sensor_type { fan, temp, vid, pll, lcd, alarm }; - -/* For each registered MaxiLife controller, we need to keep some data in - memory. It is dynamically allocated, at the same time when a new MaxiLife - client is allocated. We assume MaxiLife will only be present on the - SMBus and not on the ISA bus. */ -struct maxi_data { - struct i2c_client client; - int sysctl_id; - enum maxi_type type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 fan[4]; /* Register value */ - u8 fan_min[4]; /* Register value */ - u8 fan_speed[4]; /* Register value */ - u8 fan_div[4]; /* Static value */ - u8 temp[6]; /* Register value */ - u8 temp_max[6]; /* Static value */ - u8 temp_hyst[6]; /* Static value */ - u8 pll; /* Register value */ - u8 pll_min; /* Register value */ - u8 pll_max; /* register value */ - u8 vid[5]; /* Register value */ - u8 vid_min[5]; /* Register value */ - u8 vid_max[5]; /* Register value */ - u8 lcd[4][17]; /* Four LCD lines */ - u16 alarms; /* Register encoding, combined */ -}; - - -static int maxi_attach_adapter(struct i2c_adapter *adapter); -static int maxi_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int maxi_detach_client(struct i2c_client *client); - -static int maxi_read_value(struct i2c_client *client, u8 register); -static int maxi_read_token(struct i2c_client *client, u16 token); -#ifndef NOWRITE -static int maxi_write_value(struct i2c_client *client, u8 register, - u8 value); -#endif -static int maxi_write_token_loop(struct i2c_client *client, u16 token, - u8 len, u8 * values); - -static void maxi_update_client(struct i2c_client *client); -static void maxi99_update_client(struct i2c_client *client, - enum sensor_type sensor, int which); -static void maxi_init_client(struct i2c_client *client); - -static void maxi_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void maxi99_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void maxi_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void maxi99_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void maxi_pll(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void maxi_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void maxi99_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void maxi_lcd(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void maxi_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* The driver. I choose to use type i2c_driver, as at is identical to - the smbus_driver. */ -static struct i2c_driver maxi_driver = { - .name = "HP MaxiLife driver", - .id = I2C_DRIVERID_MAXILIFE, - .flags = I2C_DF_NOTIFY, - .attach_adapter = maxi_attach_adapter, - .detach_client = maxi_detach_client, -}; - -/* Default firmware version. Use module option "maxi_version" - to set desired version. Auto detect is not yet working */ -static int maxi_version = cristal; - -/* The /proc/sys entries */ - -/* -- SENSORS SYSCTL START -- */ -#define MAXI_SYSCTL_FAN1 1101 /* Rotations/min */ -#define MAXI_SYSCTL_FAN2 1102 /* Rotations/min */ -#define MAXI_SYSCTL_FAN3 1103 /* Rotations/min */ -#define MAXI_SYSCTL_FAN4 1104 /* Rotations/min */ -#define MAXI_SYSCTL_TEMP1 1201 /* Degrees Celsius */ -#define MAXI_SYSCTL_TEMP2 1202 /* Degrees Celsius */ -#define MAXI_SYSCTL_TEMP3 1203 /* Degrees Celsius */ -#define MAXI_SYSCTL_TEMP4 1204 /* Degrees Celsius */ -#define MAXI_SYSCTL_TEMP5 1205 /* Degrees Celsius */ -#define MAXI_SYSCTL_TEMP6 1206 /* Degrees Celsius */ -#define MAXI_SYSCTL_PLL 1301 /* MHz */ -#define MAXI_SYSCTL_VID1 1401 /* Volts / 6.337, for nba just Volts */ -#define MAXI_SYSCTL_VID2 1402 /* Volts */ -#define MAXI_SYSCTL_VID3 1403 /* Volts */ -#define MAXI_SYSCTL_VID4 1404 /* Volts */ -#define MAXI_SYSCTL_VID5 1405 /* Volts */ -#define MAXI_SYSCTL_LCD1 1501 /* Line 1 of LCD */ -#define MAXI_SYSCTL_LCD2 1502 /* Line 2 of LCD */ -#define MAXI_SYSCTL_LCD3 1503 /* Line 3 of LCD */ -#define MAXI_SYSCTL_LCD4 1504 /* Line 4 of LCD */ -#define MAXI_SYSCTL_ALARMS 2001 /* Bitvector (see below) */ - -#define MAXI_ALARM_VID4 0x0001 -#define MAXI_ALARM_TEMP2 0x0002 -#define MAXI_ALARM_VID1 0x0004 -#define MAXI_ALARM_VID2 0x0008 -#define MAXI_ALARM_VID3 0x0010 -#define MAXI_ALARM_PLL 0x0080 -#define MAXI_ALARM_TEMP4 0x0100 -#define MAXI_ALARM_TEMP5 0x0200 -#define MAXI_ALARM_FAN1 0x1000 -#define MAXI_ALARM_FAN2 0x2000 -#define MAXI_ALARM_FAN3 0x4000 - -#define MAXI_ALARM_FAN 0x0100 /* To be used with MaxiLife'99 */ -#define MAXI_ALARM_VID 0x0200 /* The MSB specifies which sensor */ -#define MAXI_ALARM_TEMP 0x0400 /* in the alarm group failed, i.e.: */ -#define MAXI_ALARM_VADD 0x0800 /* 0x0402 = TEMP2 failed = CPU2 temp */ - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected MaxiLife processor. - This is just a template; though at first sight, you might think we - could use a statically allocated list, we need some way to get back - to the parent - which is done through one of the 'extra' fields - which are initialized when a new copy is allocated. */ -static ctl_table maxi_dir_table_template[] = { - {MAXI_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_fan}, - {MAXI_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_fan}, - {MAXI_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_fan}, - {MAXI_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_fan}, - {MAXI_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_temp}, - {MAXI_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_temp}, - {MAXI_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_temp}, - {MAXI_SYSCTL_TEMP4, "temp4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_temp}, - {MAXI_SYSCTL_TEMP5, "temp5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_temp}, - {MAXI_SYSCTL_TEMP6, "temp6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_temp}, - {MAXI_SYSCTL_PLL, "pll", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_pll}, - {MAXI_SYSCTL_VID1, "vid1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_vid}, - {MAXI_SYSCTL_VID2, "vid2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_vid}, - {MAXI_SYSCTL_VID3, "vid3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_vid}, - {MAXI_SYSCTL_VID4, "vid4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_vid}, - {MAXI_SYSCTL_VID5, "vid5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_vid}, - {MAXI_SYSCTL_LCD1, "lcd1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_lcd}, - {MAXI_SYSCTL_LCD2, "lcd2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_lcd}, - {MAXI_SYSCTL_LCD3, "lcd3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_lcd}, - {MAXI_SYSCTL_LCD4, "lcd4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_lcd}, - {MAXI_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &maxi_alarms}, - {0} -}; - -/* This function is called when: - - maxi_driver is inserted (when this module is loaded), for each - available adapter - - when a new adapter is inserted (and maxi_driver is still present) */ -static int maxi_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, maxi_detect); -} - -/* This function is called by i2c_detect */ -int maxi_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - struct i2c_client *new_client; - struct maxi_data *data; - enum maxi_type type = 0; - int i, j, err = 0; - const char *type_name = NULL, *client_name = NULL; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access maxi_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct maxi_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - /* Fill the new client structure with data */ - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &maxi_driver; - new_client->flags = 0; - - /* Now we do the remaining detection. */ - if (kind < 0) { - if (i2c_smbus_read_byte_data - (new_client, MAXI_REG_MBX_STATUS) < 0) - goto ERROR2; - } - - /* Determine the chip type - only one kind supported */ - if (kind <= 0) - kind = maxilife; - - if (kind == maxilife) { - /* Detect if the machine has a MaxiLife NBA controller. - The right way to perform this check is to do a read/modify/write - on register MbxStatus (5A): - - Read 5A (value 0 for non-NBA firmware, FF (MbxIdle on NBA-firmware) - - Write 55 on 5A, then read back 5A - Non-NBA firmware: value is 55 (reg 5A is a standard writable reg) - NBA firmaware: value is FF (write-protect on MbxStatus active) */ - int stat; - i2c_smbus_write_byte_data(new_client, MAXI_REG_MBX_STATUS, - 0x55); - stat = - i2c_smbus_read_byte_data(new_client, - MAXI_REG_MBX_STATUS); - - /*if (stat == MAXI_STAT_IDLE || stat == MAXI_STAT_OK) */ - if (stat != 0x55) - maxi_version = nba; -#ifdef AUTODETECT - else { - /* The right way to get the platform info is to read the firmware - revision from serial EEPROM (addr=0x54), at offset 0x0045. - This is a string as: - "CG 00.04" -> Cristal [XU] / Geronimo [XAs] - "CO 00.03" -> Cognac [XU] - "AS 00.01" -> Ashaki [XA] */ -#if 0 - int biosctl; - biosctl = - i2c_smbus_read_byte_data(new_client, - MAXI_REG_BIOS_CTRL); - i2c_smbus_write_byte_data(new_client, - MAXI_REG_BIOS_CTRL, - biosctl | 4); - err = eeprom_read_byte_data(adapter, 0x54, 0x45); - i2c_smbus_write_byte_data(new_client, - MAXI_REG_BIOS_CTRL, - biosctl); -#endif - int i; - char *biosmem, *bm; - bm = biosmem = ioremap(0xe0000, 0x20000); - if (biosmem) { - printk("begin of bios search\n"); - for (i = 0; i < 0x20000; i++) { - if (*bm == 'C') { - char *s = bm; - while (s && isprint(*s)) { - printk("%c", *s); - s++; - } - printk("\n"); - if (!strncmp - (bm, "CG 00.04", 8)) { - maxi_version = - cristal; - printk - ("maxilife: found MaxiLife Rev CG 00.04\n"); - break; - } - if (!strncmp - (bm, "CO 00.03", 8)) { - maxi_version = - cognac; - printk - ("maxilife: found MaxiLife Rev CO 00.03\n"); - break; - } - } - if (*bm == 'A' && *(bm + 1) == 'S') { - char *s = bm; - while (s && isprint(*s)) { - printk("%c", *s); - s++; - } - printk("\n"); - if (!strncmp - (bm, "AS 00.01", 8)) { - maxi_version = - ashaki; - printk - ("maxilife: found MaxiLife Rev AS 00.01\n"); - break; - } - } - bm++; - } - printk("end of bios search\n"); - } else - printk("could not map bios memory\n"); - } -#endif - - if (maxi_version == cristal) { - type = cristal; - type_name = "maxilife-cg"; - client_name = "HP MaxiLife Rev CG 00.04"; - printk - ("maxilife: HP KAYAK XU/XAs (Dual Pentium II Slot 1)\n"); - } else if (maxi_version == cognac) { - type = cognac; - type_name = "maxilife-co"; - client_name = "HP MaxiLife Rev CO 00.03"; - printk - ("maxilife: HP KAYAK XU (Dual Xeon Slot 2 400/450 Mhz)\n"); - } else if (maxi_version == ashaki) { - type = ashaki; - type_name = "maxilife-as"; - client_name = "HP MaxiLife Rev AS 00.01"; - printk - ("maxilife: HP KAYAK XA (Pentium II Slot 1, monoprocessor)\n"); - } else if (maxi_version == nba) { - type = nba; - type_name = "maxilife-nba"; - client_name = "HP MaxiLife NBA"; - printk("maxilife: HP KAYAK XU800/XM600\n"); - } else { -#ifdef AUTODETECT - printk - ("maxilife: Warning: probed non-maxilife chip?!? (%x)\n", - err); -#else - printk - ("maxilife: Error: specified wrong maxi_version (%d)\n", - maxi_version); -#endif - goto ERROR2; - } - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - ((struct maxi_data *) (new_client->data))->type = type; - - for (i = 0; i < 4; i++) - for (j = 0; j < 17; j++) - ((struct maxi_data *) (new_client->data))-> - lcd[i][j] = (u8) 0; - - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell i2c-core that a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR2; - - /* Register a new directory entry with module sensors */ - if ((err = i2c_register_entry(new_client, type_name, - maxi_dir_table_template, - THIS_MODULE)) < 0) - goto ERROR4; - data->sysctl_id = err; - - /* Initialize the MaxiLife chip */ - maxi_init_client(new_client); - return 0; - - /* OK, this is not exactly good programming practice, usually. - But it is very code-efficient in this case. */ - ERROR4: - i2c_detach_client(new_client); - ERROR2: - kfree(data); - ERROR0: - return err; -} - -/* This function is called whenever a client should be removed: - - maxi_driver is removed (when this module is unloaded) - - when an adapter is removed which has a maxi client (and maxi_driver - is still present). */ -static int maxi_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct maxi_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("maxilife: Client deregistration failed, client not detached.\n"); - return err; - } - kfree(client->data); - return 0; -} - -/* Read byte from specified register (-1 in case of error, value otherwise). */ -static int maxi_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -/* Read the byte value for a MaxiLife token (-1 in case of error, value otherwise */ -static int maxi_read_token(struct i2c_client *client, u16 token) -{ - u8 lowToken, highToken; - int error, value; - - lowToken = LOW(token); - highToken = HIGH(token); - - /* Set mailbox status register to idle state. */ - error = - i2c_smbus_write_byte_data(client, MAXI_REG_MBX_STATUS, - MAXI_STAT_IDLE); - if (error < 0) - return error; - - /* Check for mailbox idle state. */ - error = i2c_smbus_read_byte_data(client, MAXI_REG_MBX_STATUS); - if (error != MAXI_STAT_IDLE) - return -1; - - /* Write the most significant byte of the token we want to read. */ - error = - i2c_smbus_write_byte_data(client, MAXI_REG_MBX_TOKEN_H, - highToken); - if (error < 0) - return error; - - /* Write the least significant byte of the token we want to read. */ - error = - i2c_smbus_write_byte_data(client, MAXI_REG_MBX_TOKEN_L, - lowToken); - if (error < 0) - return error; - - /* Write the read token opcode to the mailbox. */ - error = - i2c_smbus_write_byte_data(client, MAXI_REG_MBX_CMD, - MAXI_CMD_READ); - if (error < 0) - return error; - - /* Check for transaction completion */ - do { - error = - i2c_smbus_read_byte_data(client, MAXI_REG_MBX_STATUS); - } while (error == MAXI_STAT_BUSY); - if (error != MAXI_STAT_OK) - return -1; - - /* Read the value of the token. */ - value = i2c_smbus_read_byte_data(client, MAXI_REG_MBX_DATA); - if (value == -1) - return -1; - - /* set mailbox status to idle to complete transaction. */ - error = - i2c_smbus_write_byte_data(client, MAXI_REG_MBX_STATUS, - MAXI_STAT_IDLE); - if (error < 0) - return error; - - return value; -} - -#ifndef NOWRITE -/* Write byte to specified register (-1 in case of error, 0 otherwise). */ -static int maxi_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} -#endif - -/* Write a set of len byte values to MaxiLife token (-1 in case of error, 0 otherwise). */ -int maxi_write_token_loop(struct i2c_client *client, u16 token, u8 len, - u8 * values) -{ - u8 lowToken, highToken, bCounter; - int error; - - lowToken = LOW(token); - highToken = HIGH(token); - - /* Set mailbox status register to idle state. */ - error = - i2c_smbus_write_byte_data(client, MAXI_REG_MBX_STATUS, - MAXI_STAT_IDLE); - if (error < 0) - return error; - - /* Check for mailbox idle state. */ - error = i2c_smbus_read_byte_data(client, MAXI_REG_MBX_STATUS); - if (error != MAXI_STAT_IDLE) - return -1; - - for (bCounter = 0; (bCounter < len && bCounter < 32); bCounter++) { - error = - i2c_smbus_write_byte_data(client, - (u8) (MAXI_REG_MBX_DATA + - bCounter), - values[bCounter]); - if (error < 0) - return error; - } - - /* Write the most significant byte of the token we want to read. */ - error = - i2c_smbus_write_byte_data(client, MAXI_REG_MBX_TOKEN_H, - highToken); - if (error < 0) - return error; - - /* Write the least significant byte of the token we want to read. */ - error = - i2c_smbus_write_byte_data(client, MAXI_REG_MBX_TOKEN_L, - lowToken); - if (error < 0) - return error; - - /* Write the write token opcode to the mailbox. */ - error = - i2c_smbus_write_byte_data(client, MAXI_REG_MBX_CMD, - MAXI_CMD_WRITE); - if (error < 0) - return error; - - /* Check for transaction completion */ - do { - error = - i2c_smbus_read_byte_data(client, MAXI_REG_MBX_STATUS); - } while (error == MAXI_STAT_BUSY); - if (error != MAXI_STAT_OK) - return -1; - - /* set mailbox status to idle to complete transaction. */ - return i2c_smbus_write_byte_data(client, MAXI_REG_MBX_STATUS, - MAXI_STAT_IDLE); -} - -/* Called when we have found a new MaxiLife. */ -static void maxi_init_client(struct i2c_client *client) -{ - struct maxi_data *data = client->data; - - if (data->type == nba) { - strcpy(data->lcd[2], " Linux MaxiLife"); - maxi_write_token_loop(client, MAXI_TOK_LCD(2), - strlen(data->lcd[2]) + 1, - data->lcd[2]); - } -} - -static void maxi_update_client(struct i2c_client *client) -{ - struct maxi_data *data = client->data; - int i; - - if (data->type == nba) { - printk - ("maxi_update_client should never be called by nba\n"); - return; - } - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("maxilife: Starting MaxiLife update\n"); -#endif - for (i = 0; i < 5; i++) - data->temp[i] = - maxi_read_value(client, MAXI_REG_TEMP(i)); - switch (data->type) { - case cristal: - data->temp[0] = 0; /* not valid */ - data->temp_max[0] = 0; - data->temp_hyst[0] = 0; - data->temp_max[1] = 110; /* max PCI slot temp */ - data->temp_hyst[1] = 100; - data->temp_max[2] = 120; /* max BX chipset temp */ - data->temp_hyst[2] = 110; - data->temp_max[3] = 100; /* max HDD temp */ - data->temp_hyst[3] = 90; - data->temp_max[4] = 120; /* max CPU temp */ - data->temp_hyst[4] = 110; - break; - - case cognac: - data->temp_max[0] = 120; /* max CPU1 temp */ - data->temp_hyst[0] = 110; - data->temp_max[1] = 110; /* max PCI slot temp */ - data->temp_hyst[1] = 100; - data->temp_max[2] = 120; /* max CPU2 temp */ - data->temp_hyst[2] = 110; - data->temp_max[3] = 100; /* max HDD temp */ - data->temp_hyst[3] = 90; - data->temp_max[4] = 120; /* max reference CPU temp */ - data->temp_hyst[4] = 110; - break; - - case ashaki: - data->temp[0] = 0; /* not valid */ - data->temp_max[0] = 0; - data->temp_hyst[0] = 0; - data->temp_max[1] = 110; /* max PCI slot temp */ - data->temp_hyst[1] = 100; - data->temp[2] = 0; /* not valid */ - data->temp_max[2] = 0; - data->temp_hyst[2] = 0; - data->temp_max[3] = 100; /* max HDD temp */ - data->temp_hyst[3] = 90; - data->temp_max[4] = 120; /* max CPU temp */ - data->temp_hyst[4] = 110; - break; - - default: - printk("maxilife: Unknown MaxiLife chip\n"); - } - data->temp[5] = 0; /* only used by MaxiLife'99 */ - data->temp_max[5] = 0; - data->temp_hyst[5] = 0; - - for (i = 0; i < 3; i++) { - data->fan[i] = - maxi_read_value(client, MAXI_REG_FAN(i)); - data->fan_speed[i] = - maxi_read_value(client, MAXI_REG_FAN_SPEED(i)); - data->fan_div[i] = 4; - if (data->type == ashaki) - data->fan_min[i] = - maxi_read_value(client, - MAXI_REG_FAN_MINAS(i)); - else - data->fan_min[i] = - maxi_read_value(client, - MAXI_REG_FAN_MIN(i)); - } - data->fan[3] = 0xff; /* only used by MaxiLife'99 */ - data->fan_speed[3] = 0; - data->fan_div[3] = 4; /* avoid possible /0 */ - data->fan_min[3] = 0; - - data->pll = maxi_read_value(client, MAXI_REG_PLL); - data->pll_min = maxi_read_value(client, MAXI_REG_PLL_MIN); - data->pll_max = maxi_read_value(client, MAXI_REG_PLL_MAX); - - for (i = 0; i < 4; i++) { - data->vid[i] = - maxi_read_value(client, MAXI_REG_VID(i)); - data->vid_min[i] = - maxi_read_value(client, MAXI_REG_VID_MIN(i)); - data->vid_max[i] = - maxi_read_value(client, MAXI_REG_VID_MAX(i)); - } - switch (data->type) { - case cristal: - data->vid[3] = 0; /* no voltage cache L2 */ - data->vid_min[3] = 0; - data->vid_max[3] = 0; - break; - - case cognac: - break; - - case ashaki: - data->vid[1] = 0; /* no voltage CPU 2 */ - data->vid_min[1] = 0; - data->vid_max[1] = 0; - data->vid[3] = 0; /* no voltage cache L2 */ - data->vid_min[3] = 0; - data->vid_max[3] = 0; - break; - - default: - printk("maxilife: Unknown MaxiLife chip\n"); - } - data->vid[4] = 0; /* only used by MaxliLife'99 */ - data->vid_min[4] = 0; - data->vid_max[4] = 0; - - data->alarms = maxi_read_value(client, MAXI_REG_DIAG_RT1) + - (maxi_read_value(client, MAXI_REG_DIAG_RT2) << 8); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -void maxi99_update_client(struct i2c_client *client, - enum sensor_type sensor, int which) -{ - static unsigned long last_updated[6][6]; /* sensor, which */ - struct maxi_data *data = client->data; - - down(&data->update_lock); - - /*maxi_write_token_loop(client, MAXI_TOK_LCD_LINE3, 13, "Linux 2.2.13"); */ - - if ((jiffies - last_updated[sensor][which] > 2 * HZ) || - (jiffies < last_updated[sensor][which] - || !last_updated[sensor][which])) { - - int tmp, i; - - switch (sensor) { - case fan: - for (i = 0; i < 4; i++) { - if (i == which) { - tmp = - maxi_read_token(client, - MAXI_TOK_FAN - (i)); - data->fan[i] = - maxi_read_token(client, - MAXI_TOK_FAN - (i)); - data->fan_speed[i] = - maxi_read_token(client, - MAXI_TOK_MAX - (MAXI_TOK_FAN - (i))); - data->fan_div[i] = 1; - data->fan_min[i] = 0; - } - } - break; - - case temp: - for (i = 0; i < 6; i++) { - if (i == which) { - data->temp[i] = - maxi_read_token(client, - MAXI_TOK_TEMP - (i)); - data->temp_max[i] = - maxi_read_token(client, - MAXI_TOK_MAX - (MAXI_TOK_TEMP - (i))); - data->temp_hyst[i] = - data->temp_max[i] - 5; - } - } - break; - - case vid: - for (i = 0; i < 5; i++) { - if (i == which) { - data->vid[i] = - maxi_read_token(client, - MAXI_TOK_VID - (i)); - data->vid_min[i] = - maxi_read_token(client, - MAXI_TOK_MIN - (MAXI_TOK_VID - (i))); - data->vid_max[i] = - maxi_read_token(client, - MAXI_TOK_MAX - (MAXI_TOK_VID - (i))); - } - } - break; - - case pll: - data->pll = 0; - data->pll_min = 0; - data->pll_max = 0; - break; - - case alarm: - data->alarms = - (maxi_read_token(client, MAXI_TOK_ALARM_EVENT) - << 8); - if (data->alarms) - data->alarms += - data->alarms == - (1 << 8) ? maxi_read_token(client, - MAXI_TOK_ALARM_FAN) - : data->alarms == - (2 << 8) ? maxi_read_token(client, - MAXI_TOK_ALARM_VID) - : data->alarms == - (4 << 8) ? maxi_read_token(client, - MAXI_TOK_ALARM_TEMP) - : data->alarms == - (8 << 8) ? maxi_read_token(client, - MAXI_TOK_ALARM_FAN) - : 0; - break; - - default: - printk("maxilife: Unknown sensor type\n"); - } - - last_updated[sensor][which] = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the data - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void maxi_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct maxi_data *data = client->data; - int nr; - - if (data->type == nba) { - maxi99_fan(client, operation, ctl_name, nrels_mag, - results); - return; - } - - nr = ctl_name - MAXI_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - maxi_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1]); - results[1] = data->fan_div[nr - 1]; - results[2] = FAN_FROM_REG(data->fan[nr - 1]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { -#ifndef NOWRITE - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = FAN_TO_REG(results[0]); - maxi_write_value(client, MAXI_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } -#endif - } -} - -void maxi99_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct maxi_data *data = client->data; - int nr; - - nr = ctl_name - MAXI_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - maxi99_update_client(client, fan, nr - 1); - results[0] = FAN99_FROM_REG(data->fan_min[nr - 1]); /* min rpm */ - results[1] = data->fan_div[nr - 1]; /* divisor */ - results[2] = FAN99_FROM_REG(data->fan[nr - 1]); /* rpm */ - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { -#ifndef NOWRITE - /* still to do */ - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = FAN_TO_REG(results[0]); - maxi_write_value(client, MAXI_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } -#endif - } -} - -void maxi_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct maxi_data *data = client->data; - int nr; - - if (data->type == nba) { - maxi99_temp(client, operation, ctl_name, nrels_mag, - results); - return; - } - - nr = ctl_name - MAXI_SYSCTL_TEMP1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - maxi_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_max[nr - 1]); - results[1] = TEMP_FROM_REG(data->temp_hyst[nr - 1]); - results[2] = TEMP_FROM_REG(data->temp[nr - 1]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - /* temperature range can not be changed */ - } -} - -void maxi99_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct maxi_data *data = client->data; - int nr; - - nr = ctl_name - MAXI_SYSCTL_TEMP1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - maxi99_update_client(client, temp, nr - 1); - results[0] = TEMP99_FROM_REG(data->temp_max[nr - 1]); - results[1] = TEMP99_FROM_REG(data->temp_hyst[nr - 1]); - results[2] = TEMP99_FROM_REG(data->temp[nr - 1]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - /* temperature range can not be changed */ - } -} - -void maxi_pll(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct maxi_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - if (data->type == nba) - maxi99_update_client(client, pll, 0); - else - maxi_update_client(client); - results[0] = PLL_FROM_REG(data->pll_min); - results[1] = PLL_FROM_REG(data->pll_max); - results[2] = PLL_FROM_REG(data->pll); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { -#ifndef NOWRITE - if (*nrels_mag >= 1) { - data->pll_min = PLL_TO_REG(results[0]); - maxi_write_value(client, MAXI_REG_PLL_MIN, - data->pll_min); - } - if (*nrels_mag >= 2) { - data->pll_max = PLL_TO_REG(results[1]); - maxi_write_value(client, MAXI_REG_PLL_MAX, - data->pll_max); - } -#endif - } -} - -void maxi_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct maxi_data *data = client->data; - int nr; - - if (data->type == nba) { - maxi99_vid(client, operation, ctl_name, nrels_mag, - results); - return; - } - - nr = ctl_name - MAXI_SYSCTL_VID1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 4; - else if (operation == SENSORS_PROC_REAL_READ) { - maxi_update_client(client); - results[0] = VID_FROM_REG(data->vid_min[nr - 1]); - results[1] = VID_FROM_REG(data->vid_max[nr - 1]); - results[2] = VID_FROM_REG(data->vid[nr - 1]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { -#ifndef NOWRITE - if (*nrels_mag >= 1) { - data->vid_min[nr - 1] = VID_TO_REG(results[0]); - maxi_write_value(client, MAXI_REG_VID_MIN(nr), - data->vid_min[nr - 1]); - } - if (*nrels_mag >= 2) { - data->vid_max[nr - 1] = VID_TO_REG(results[1]); - maxi_write_value(client, MAXI_REG_VID_MAX(nr), - data->vid_max[nr - 1]); - } -#endif - } -} - -void maxi99_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct maxi_data *data = client->data; - int nr = ctl_name - MAXI_SYSCTL_VID1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 4; - else if (operation == SENSORS_PROC_REAL_READ) { - maxi99_update_client(client, vid, nr - 1); - results[0] = VID99_FROM_REG(nr, data->vid_min[nr - 1]); - results[1] = VID99_FROM_REG(nr, data->vid_max[nr - 1]); - results[2] = VID99_FROM_REG(nr, data->vid[nr - 1]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { -#ifndef NOWRITE - /* still to do */ - if (*nrels_mag >= 1) { - data->vid_min[nr - 1] = VID_TO_REG(results[0]); - maxi_write_value(client, MAXI_REG_VID_MIN(nr), - data->vid_min[nr - 1]); - } - if (*nrels_mag >= 2) { - data->vid_max[nr - 1] = VID_TO_REG(results[1]); - maxi_write_value(client, MAXI_REG_VID_MAX(nr), - data->vid_max[nr - 1]); - } -#endif - } -} - -void maxi_lcd(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - /* Allows writing and reading from LCD display */ - - struct maxi_data *data = client->data; - int nr; - - if (data->type != nba) - return; - - nr = ctl_name - MAXI_SYSCTL_LCD1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = *((long *) &data->lcd[nr - 1][0]); - results[1] = *((long *) &data->lcd[nr - 1][4]); - results[2] = *((long *) &data->lcd[nr - 1][8]); - results[3] = *((long *) &data->lcd[nr - 1][12]); - *nrels_mag = 4; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - /* - Writing a string to line 3 of the LCD can be done like: - echo -n "Linux MaxiLife" | od -A n -l > \ - /proc/sys/dev/sensors/maxilife-nba-i2c-0-14/lcd3 - */ - if (*nrels_mag >= 1) - *((long *) &data->lcd[nr - 1][0]) = results[0]; - if (*nrels_mag >= 2) - *((long *) &data->lcd[nr - 1][4]) = results[1]; - if (*nrels_mag >= 3) - *((long *) &data->lcd[nr - 1][8]) = results[2]; - if (*nrels_mag >= 4) - *((long *) &data->lcd[nr - 1][12]) = results[3]; - maxi_write_token_loop(client, MAXI_TOK_LCD(nr - 1), - strlen(data->lcd[nr - 1]) + 1, - data->lcd[nr - 1]); -#if 0 - if (*nrels_mag >= 1) - printk("nr=%d, result[0] = %.4s\n", nr, - (char *) &results[0]); - if (*nrels_mag >= 2) - printk("nr=%d, result[1] = %.4s\n", nr, - (char *) &results[1]); - if (*nrels_mag >= 3) - printk("nr=%d, result[2] = %.4s\n", nr, - (char *) &results[2]); - if (*nrels_mag >= 4) - printk("nr=%d, result[3] = %.4s\n", nr, - (char *) &results[3]); -#endif - } - -} - -void maxi_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct maxi_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - if (data->type == nba) - maxi99_update_client(client, alarm, 0); - else - maxi_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -static int __init sm_maxilife_init(void) -{ - printk("maxilife: Version %s (lm_sensors %s (%s))\n", version_str, - LM_VERSION, LM_DATE); - return i2c_add_driver(&maxi_driver); -} - -static void __exit sm_maxilife_exit(void) -{ - i2c_del_driver(&maxi_driver); -} - - - -MODULE_AUTHOR("Fons Rademakers "); -MODULE_DESCRIPTION("HP MaxiLife driver"); -MODULE_PARM(maxi_version, "i"); -MODULE_PARM_DESC(maxi_version, "MaxiLife firmware version"); - -module_init(sm_maxilife_init); -module_exit(sm_maxilife_exit); diff --git a/kernel/chips/mic74.c b/kernel/chips/mic74.c deleted file mode 100644 index b04a6bbe..00000000 --- a/kernel/chips/mic74.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - mic74.c - Intended to become part of lm_sensors, Linux - kernel modules for hardware monitoring - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* Supports Micrel MIC74 */ - -/* - A couple notes about the MIC74: -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x20, 0x27, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(mic74); - -/* The mic74 registers */ - -#define MIC74_REG_CONFIG 0x00 -#define MIC74_REG_DATA_DIR 0x01 -#define MIC74_REG_OUT_CFG 0x02 -#define MIC74_REG_STATUS 0x03 -#define MIC74_REG_INT_MASK 0x04 -#define MIC74_REG_DATA 0x05 -#define MIC74_REG_FAN_SPEED 0x06 - -/* Initial values */ -/* All registers are 0, except for MIC74_REG_DATA which is 0xFF */ - -/* For each registered MIC74, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new mic74 client is - allocated. */ -struct mic74_data { - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 config; /* Register value */ - u8 dataDir; /* Register value */ - u8 outCfg; /* Register value */ - u8 status; /* Register value */ - u8 intMask; /* Register value */ - u8 data; /* Register value */ - u8 fanSpeed; /* Register value */ -}; - -static int mic74_attach_adapter(struct i2c_adapter *adapter); -static int mic74_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int mic74_detach_client(struct i2c_client *client); - -static int mic74_read_value(struct i2c_client *client, u8 register); -static int mic74_write_value(struct i2c_client *client, u8 register, - u8 value); -static void mic74_update_client(struct i2c_client *client); -static void mic74_init_client(struct i2c_client *client); - -static void mic74_reg_rw(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void mic74_reg_ro(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); - -/* I choose here for semi-static MIC74 allocation. Complete dynamic - allocation could also be used; the code needed for this would probably - take more memory than the datastructure takes now. */ -static int mic74_id; - -static struct i2c_driver mic74_driver = { - .name = "MIC74 sensor driver", - .flags = I2C_DF_NOTIFY, - .attach_adapter = mic74_attach_adapter, - .detach_client = mic74_detach_client -}; - -/* -- SENSORS SYSCTL START -- */ -#define MIC74_SYSCTL_REG0 1000 -#define MIC74_SYSCTL_REG1 1001 -#define MIC74_SYSCTL_REG2 1002 -#define MIC74_SYSCTL_REG3 1003 -#define MIC74_SYSCTL_REG4 1004 -#define MIC74_SYSCTL_REG5 1005 -#define MIC74_SYSCTL_REG6 1006 -/* -- SENSORS SYSCTL END -- */ - -/* The /proc/sys entries */ -/* These files are created for each detected MIC74. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table mic74_dir_table_template[] = { - {MIC74_SYSCTL_REG0, /* ctl_name */ - "dev_cfg", /* procname */ - NULL, /* data */ - 0, /* maxlen */ - 0644, /* mode */ - NULL, /* child */ - &i2c_proc_real, /* proc_handler */ - &i2c_sysctl_real, /* strategy */ - NULL, /* de */ - &mic74_reg_rw }, /* extra1, extra2 is by default NULL? */ - {MIC74_SYSCTL_REG1, "dir", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &mic74_reg_rw }, - {MIC74_SYSCTL_REG2, "out_cfg", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &mic74_reg_rw }, - {MIC74_SYSCTL_REG3, "status", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &mic74_reg_ro }, - {MIC74_SYSCTL_REG4, "int_mask", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &mic74_reg_rw }, - {MIC74_SYSCTL_REG5, "data", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &mic74_reg_rw }, - {MIC74_SYSCTL_REG6, "fan_speed", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &mic74_reg_rw }, - {0} -}; - -int mic74_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, mic74_detect); -} - -static int mic74_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct mic74_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access mic74_{read,write}_value. */ - - if (!(new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct mic74_data), - GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - data = (struct mic74_data *) (new_client + 1); - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &mic74_driver; - new_client->flags = 0; -#ifdef CONFIG_AMAZON - /* make sure we can search for the client later */ - new_client->flags |= I2C_CLIENT_ALLOW_USE; -#endif - - /* Determine the chip type - only one kind */ - if (kind <= 0) - kind = mic74; - - if (kind == mic74) { - type_name = "mic74"; - client_name = "MIC74 chip"; - } - else { - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - - new_client->id = mic74_id++; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - mic74_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the MIC74 chip */ - mic74_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(new_client); - ERROR0: - printk("mic74.o: mic74_detect failed\n"); - return err; -} - -int mic74_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct mic74_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("mic74.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client); - return 0; -} - -int mic74_read_value(struct i2c_client *client, u8 reg) -{ - return 0xFF & i2c_smbus_read_byte_data(client, reg); -} - -int mic74_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new MIC74. */ -void mic74_init_client(struct i2c_client *client) -{ - /* don't init, defaults are fine */ -} - -void mic74_update_client(struct i2c_client *client) -{ - struct mic74_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ) || - (jiffies < data->last_updated) || - !data->valid) { - -#ifdef DEBUG - printk("Starting mic74 update\n"); -#endif - data->config = mic74_read_value(client, MIC74_REG_CONFIG); - data->dataDir = mic74_read_value(client, MIC74_REG_DATA_DIR); - data->outCfg = mic74_read_value(client, MIC74_REG_OUT_CFG); - data->status = mic74_read_value(client, MIC74_REG_STATUS); - data->intMask = mic74_read_value(client, MIC74_REG_INT_MASK); - data->data = mic74_read_value(client, MIC74_REG_DATA); - data->fanSpeed = mic74_read_value(client, MIC74_REG_FAN_SPEED); - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void mic74_reg_rw(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct mic74_data *data = client->data; - - int nr = ctl_name - MIC74_SYSCTL_REG0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - - mic74_update_client(client); - - switch (nr) { - case 0: - results[0] = data->config; - break; - case 1: - results[0] = data->dataDir; - break; - case 2: - results[0] = data->outCfg; - break; - case 3: - results[0] = data->status; - break; - case 4: - results[0] = data->intMask; - break; - case 5: - results[0] = data->data; - break; - case 6: - results[0] = data->fanSpeed; - break; - } - - *nrels_mag = 1; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - - if (*nrels_mag >= 1) - mic74_write_value(client, - (u8)nr, - (u8)(results[0] & 0xFF)); - } -} - -/* This is identical to the above except that it has now - WRITE code and it calls the _rw routine above for a READ */ -void mic74_reg_ro(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - - mic74_reg_rw(client, operation, ctl_name, - nrels_mag, results); - *nrels_mag = 1; - } -} - -static int __init sensors_mic74_init(void) -{ - printk("mic74.o version %s (%s)\n", LM_VERSION, LM_DATE); - return(i2c_add_driver(&mic74_driver)); -} - -static void __init mic74_cleanup(void) -{ - i2c_del_driver(&mic74_driver); -} - -MODULE_AUTHOR("zebo25/MDS"); -MODULE_DESCRIPTION("MIC74 driver"); - -module_init(sensors_mic74_init); -module_exit(mic74_cleanup); diff --git a/kernel/chips/mtp008.c b/kernel/chips/mtp008.c deleted file mode 100644 index 2d1d9de7..00000000 --- a/kernel/chips/mtp008.c +++ /dev/null @@ -1,1098 +0,0 @@ -/* - mtp008.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (C) 2001, 2004 Kris Van Hees - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = {SENSORS_I2C_END}; -static unsigned short normal_i2c_range[] = {0x2c, 0x2e, SENSORS_I2C_END}; -static unsigned int normal_isa[] = {SENSORS_ISA_END}; -static unsigned int normal_isa_range[] = {SENSORS_ISA_END}; - -/* Insmod parameters */ -SENSORS_INSMOD_1(mtp008); - -/* The MTP008 registers */ -/* in0 .. in6 */ -#define MTP008_REG_IN(nr) (0x20 + (nr)) -#define MTP008_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define MTP008_REG_IN_MIN(nr) (0x2c + (nr) * 2) - -/* temp1 */ -#define MTP008_REG_TEMP 0x27 -#define MTP008_REG_TEMP_MAX 0x39 -#define MTP008_REG_TEMP_MIN 0x3a - -/* fan1 .. fan3 */ -#define MTP008_REG_FAN(nr) (0x27 + (nr)) -#define MTP008_REG_FAN_MIN(nr) (0x3a + (nr)) - -#define MTP008_REG_CONFIG 0x40 -#define MTP008_REG_INT_STAT1 0x41 -#define MTP008_REG_INT_STAT2 0x42 - -#define MTP008_REG_SMI_MASK1 0x43 -#define MTP008_REG_SMI_MASK2 0x44 - -#define MTP008_REG_NMI_MASK1 0x45 -#define MTP008_REG_NMI_MASK2 0x46 - -#define MTP008_REG_VID_FANDIV 0x47 - -#define MTP008_REG_I2C_ADDR 0x48 - -#define MTP008_REG_RESET_VID4 0x49 - -#define MTP008_REG_OVT_PROP 0x50 - -#define MTP008_REG_BEEP_CTRL1 0x51 -#define MTP008_REG_BEEP_CTRL2 0x52 - -/* pwm1 .. pwm3 nr range 1-3 */ -#define MTP008_REG_PWM_CTRL(nr) (0x52 + (nr)) - -#define MTP008_REG_PIN_CTRL1 0x56 -#define MTP008_REG_PIN_CTRL2 0x57 - -#define MTP008_REG_CHIPID 0x58 - -/* - * Pin control register configuration constants. - */ -#define MTP008_CFG_VT1_PII 0x08 -#define MTP008_CFG_VT2_AIN 0x00 -#define MTP008_CFG_VT2_VT 0x03 -#define MTP008_CFG_VT2_PII 0x04 -#define MTP008_CFG_VT2_MASK 0x06 -#define MTP008_CFG_VT3_VT 0x01 - -/* sensor pin types */ -#define VOLTAGE 1 -#define THERMISTOR 2 -#define PIIDIODE 3 - -/* - * Conversion routines and macros. Limit checking is only done on - * the TO_REG variants. - * - * Note that IN values are expressed as 100 times the actual voltage to avoid - * having to use floating point values. As such, IN values are between 0 and - * 409 (0V to 4.096V). - */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8) / 16), 0, 255)) -#define IN_FROM_REG(val) (((val) * 16 + 5) / 10) - -/* - * The fan cotation count (as stored in the register) is calculated using the - * following formula: - * count = (22.5K * 60) / (rpm * div) = 1350000 / (rpm * div) - * and the rpm is therefore: - * rpm = 1350000 / (count * div) - */ -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - - return SENSORS_LIMIT( - (1350000 + rpm * div / 2) / (rpm * div), - 1, 254 - ); -} - -#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 \ - : (val) == 255 ? 0 \ - : 1350000 / \ - ((val) * (div)) \ - ) - -/* - * Temperatures are stored as two's complement values of the Celsius value. It - * actually uses 10 times the Celsius value to avoid using floating point - * values. - */ -#define TEMP_TO_REG(val) ( \ - (val) < 0 \ - ? SENSORS_LIMIT(((val) - 5) / 10, 0, 255) \ - : SENSORS_LIMIT(((val) + 5) / 10, 0, 255) \ - ) -#define TEMP_FROM_REG(val) ( \ - ( \ - (val) > 0x80 ? (val) - 0x100 \ - : (val) \ - ) * 10 \ - ) - -/* - * VCORE voltage: - * 0x00 to 0x0f = 2.05 to 1.30 (0.05 per unit) - * 0x10 to 0x1e = 3.50 to 2.10 (0.10 per unit) - * 0x1f = No CPU - */ -#define VID_FROM_REG(val) ((val) == 0x1f \ - ? 0 \ - : (val) < 0x10 ? 205 - (val) * 5 \ - : 510 - (val) * 10) - -/* - * Fan divider. - */ -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val) == 8 ? 3 \ - : (val) == 4 ? 2 \ - : (val) == 2 ? 1 \ - : 0) - -/* - * Alarms (interrupt status). - */ -#define ALARMS_FROM_REG(val) (val) - -/* - * Beep controls. - */ -#define BEEPS_FROM_REG(val) (val) -#define BEEPS_TO_REG(val) (val) - -/* - * PWM control. nr range 1 to 3 - */ -#define PWM_FROM_REG(val) (val) -#define PWM_TO_REG(val) (val) -#define PWMENABLE_FROM_REG(nr, val) (((val) >> ((nr) + 3)) & 1) - -/* - * For each registered MTP008, we need to keep some data in memory. The - * structure itself is dynamically allocated, at the same time when a new - * mtp008 client is allocated. - */ -struct mtp008_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 temp; /* Register value */ - u8 temp_max; /* Register value */ - u8 temp_min; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 vid; /* Register encoding */ - u8 fan_div[3]; /* Register encoding */ - u16 alarms; /* Register encoding */ - u16 beeps; /* Register encoding */ - u8 pwm[4]; /* Register value */ - u8 sens[3]; /* 1 = Analog input, - 2 = Thermistor, - 3 = PII/Celeron diode */ - u8 pwmenable; /* Register 0x57 value */ -}; - -static int mtp008_attach_adapter(struct i2c_adapter *adapter); -static int mtp008_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int mtp008_detach_client(struct i2c_client *client); - -static int mtp008_read_value(struct i2c_client *client, u8 register); -static int mtp008_write_value(struct i2c_client *client, u8 register, u8 value); -static void mtp008_update_client(struct i2c_client *client); -static void mtp008_init_client(struct i2c_client *client); - -static void mtp008_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_beep(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_sens(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void mtp008_getsensortype(struct mtp008_data *data, u8 inp); - -static struct i2c_driver mtp008_driver = -{ - .name = "MTP008 sensor driver", - .id = I2C_DRIVERID_MTP008, - .flags = I2C_DF_NOTIFY, - .attach_adapter = mtp008_attach_adapter, - .detach_client = mtp008_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define MTP008_SYSCTL_IN0 1000 /* Volts * 100 */ -#define MTP008_SYSCTL_IN1 1001 -#define MTP008_SYSCTL_IN2 1002 -#define MTP008_SYSCTL_IN3 1003 -#define MTP008_SYSCTL_IN4 1004 -#define MTP008_SYSCTL_IN5 1005 -#define MTP008_SYSCTL_IN6 1006 -#define MTP008_SYSCTL_FAN1 1101 /* Rotations/min */ -#define MTP008_SYSCTL_FAN2 1102 -#define MTP008_SYSCTL_FAN3 1103 -#define MTP008_SYSCTL_TEMP1 1200 /* Degrees Celsius * 10 */ -#define MTP008_SYSCTL_TEMP2 1201 /* Degrees Celsius * 10 */ -#define MTP008_SYSCTL_TEMP3 1202 /* Degrees Celsius * 10 */ -#define MTP008_SYSCTL_VID 1300 /* Volts * 100 */ -#define MTP008_SYSCTL_PWM1 1401 -#define MTP008_SYSCTL_PWM2 1402 -#define MTP008_SYSCTL_PWM3 1403 -#define MTP008_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */ -#define MTP008_SYSCTL_SENS2 1502 -#define MTP008_SYSCTL_SENS3 1503 -#define MTP008_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define MTP008_SYSCTL_ALARMS 2001 /* bitvector */ -#define MTP008_SYSCTL_BEEP 2002 /* bitvector */ - -#define MTP008_ALARM_IN0 0x0001 -#define MTP008_ALARM_IN1 0x0002 -#define MTP008_ALARM_IN2 0x0004 -#define MTP008_ALARM_IN3 0x0008 -#define MTP008_ALARM_IN4 0x0100 -#define MTP008_ALARM_IN5 0x0200 -#define MTP008_ALARM_IN6 0x0400 -#define MTP008_ALARM_FAN1 0x0040 -#define MTP008_ALARM_FAN2 0x0080 -#define MTP008_ALARM_FAN3 0x0800 -#define MTP008_ALARM_TEMP1 0x0010 -#define MTP008_ALARM_TEMP2 0x0100 -#define MTP008_ALARM_TEMP3 0x0200 - -/* -- SENSORS SYSCTL END -- */ - -/* The /proc/sys entries */ -/* These files are created for each detected chip. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ - -static ctl_table mtp008_dir_table_template[] = -{ - {MTP008_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in}, - {MTP008_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in}, - {MTP008_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in}, - {MTP008_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in}, - {MTP008_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in}, - {MTP008_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in}, - {MTP008_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_in}, - {MTP008_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan}, - {MTP008_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan}, - {MTP008_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan}, - {MTP008_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_temp}, - {MTP008_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_temp_add}, - {MTP008_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_temp_add}, - {MTP008_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_vid}, - {MTP008_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_fan_div}, - {MTP008_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_alarms}, - {MTP008_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_beep}, - {MTP008_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_pwm}, - {MTP008_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_pwm}, - {MTP008_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_pwm}, - {MTP008_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_sens}, - {MTP008_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_sens}, - {MTP008_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &mtp008_sens}, - {0} -}; - -/* This function is called when: - * mtp008_driver is inserted (when this module is loaded), for each available - * adapter when a new adapter is inserted (and mtp008_driver is still present) - */ -static int mtp008_attach_adapter(struct i2c_adapter *adapter) -{ - struct i2c_client_address_data mtp008_addr_data; - - mtp008_addr_data.normal_i2c = addr_data.normal_i2c; - mtp008_addr_data.normal_i2c_range = addr_data.normal_i2c_range; - mtp008_addr_data.probe = addr_data.probe; - mtp008_addr_data.probe_range = addr_data.probe_range; - mtp008_addr_data.ignore = addr_data.ignore; - mtp008_addr_data.ignore_range = addr_data.ignore_range; - mtp008_addr_data.force = addr_data.forces->force; - - return i2c_probe(adapter, &mtp008_addr_data, mtp008_detect); -} - -int mtp008_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - const char *type_name = ""; - const char *client_name = ""; - int is_isa, err, sysid; - struct i2c_client *new_client; - struct mtp008_data *data; - - err = 0; - - is_isa = i2c_is_isa_adapter(adapter); - if (is_isa || - !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* - * We presume we have a valid client. We now create the client - * structure, even though we cannot fill it completely yet. But it - * allows us to use mtp008_(read|write)_value(). - */ - if (!(data = kmalloc(sizeof(struct mtp008_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &mtp008_driver; - new_client->flags = 0; - - /* - * Remaining detection. - */ - if (kind < 0) { - if (mtp008_read_value(new_client, MTP008_REG_CHIPID) != 0xac) - goto ERROR1; - } - /* - * Fill in the remaining client fields and put it into the global list. - */ - type_name = "mtp008"; - client_name = "MTP008 chip"; - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* - * Tell the I2C layer that a new client has arrived. - */ - if ((err = i2c_attach_client(new_client))) - goto ERROR1; - - /* - * Register a new directory entry with the sensors module. - */ - if ((sysid = i2c_register_entry(new_client, type_name, - mtp008_dir_table_template, - THIS_MODULE)) < 0) { - err = sysid; - goto ERROR2; - } - data->sysctl_id = sysid; - - /* - * Initialize the MTP008 chip. - */ - mtp008_init_client(new_client); - - return 0; - - /* - * Error handling. Bad programming practise but very code efficient. - */ - ERROR2: - i2c_detach_client(new_client); - ERROR1: - kfree(data); - - ERROR0: - return err; -} - -static int mtp008_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry( - ((struct mtp008_data *) (client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("mtp008.o: Deregistration failed, " - "client not detached.\n"); - return err; - } - kfree(client->data); - - return 0; -} - - -static int mtp008_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg) & 0xff; -} - -static int mtp008_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -/* Called when we have found a new MTP008. */ -static void mtp008_init_client(struct i2c_client *client) -{ - u8 save1, save2; - struct mtp008_data *data; - - data = client->data; - - /* - * Initialize the Myson MTP008 hardware monitoring chip. - * Save the pin settings that the BIOS hopefully set. - */ - save1 = mtp008_read_value(client, MTP008_REG_PIN_CTRL1); - save2 = mtp008_read_value(client, MTP008_REG_PIN_CTRL2); - mtp008_write_value(client, MTP008_REG_CONFIG, - (mtp008_read_value(client, MTP008_REG_CONFIG) & 0x7f) | 0x80); - mtp008_write_value(client, MTP008_REG_PIN_CTRL1, save1); - mtp008_write_value(client, MTP008_REG_PIN_CTRL2, save2); - - mtp008_getsensortype(data, save2); - - - /* - * Start monitoring. - */ - mtp008_write_value( - client, MTP008_REG_CONFIG, - (mtp008_read_value(client, MTP008_REG_CONFIG) & 0xf7) | 0x01 - ); -} - -static void mtp008_update_client(struct i2c_client *client) -{ - int i; - u8 inp; - struct mtp008_data *data; - - data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { -#ifdef DEBUG - printk("Starting MTP008 update\n"); -#endif - - /* - * Read in the analog inputs. We're reading AIN4 and AIN5 as - * regular analog inputs, even though they may have been - * configured as temperature readings instead. Interpretation - * of these values is done elsewhere. - */ - for (i = 0; i < 7; i++) { - data->in[i] = - mtp008_read_value(client, MTP008_REG_IN(i)); - data->in_max[i] = - mtp008_read_value(client, MTP008_REG_IN_MAX(i)); - data->in_min[i] = - mtp008_read_value(client, MTP008_REG_IN_MIN(i)); - } - - /* - * Read the temperature sensor. - */ - data->temp = mtp008_read_value(client, MTP008_REG_TEMP); - data->temp_max = mtp008_read_value(client, MTP008_REG_TEMP_MAX); - data->temp_min = mtp008_read_value(client, MTP008_REG_TEMP_MIN); - - /* - * Read the first 2 fan dividers and the VID setting. Read the - * third fan divider from a different register. - */ - inp = mtp008_read_value(client, MTP008_REG_VID_FANDIV); - data->vid = inp & 0x0f; - data->vid |= (mtp008_read_value(client, - MTP008_REG_RESET_VID4) & 0x01) << 4; - - data->fan_div[0] = (inp >> 4) & 0x03; - data->fan_div[1] = inp >> 6; - data->fan_div[2] = - mtp008_read_value(client, MTP008_REG_PIN_CTRL1) >> 6; - - /* - * Read the interrupt status registers. - */ - data->alarms = - (mtp008_read_value(client, - MTP008_REG_INT_STAT1) & 0xdf) | - (mtp008_read_value(client, - MTP008_REG_INT_STAT2) & 0x0f) << 8; - - /* - * Read the beep control registers. - */ - data->beeps = - (mtp008_read_value(client, - MTP008_REG_BEEP_CTRL1) & 0xdf) | - (mtp008_read_value(client, - MTP008_REG_BEEP_CTRL2) & 0x8f) << 8; - - /* - * Read the sensor configuration. - */ - inp = mtp008_read_value(client, MTP008_REG_PIN_CTRL2); - mtp008_getsensortype(data, inp); - data->pwmenable = inp; - - /* - * Read the PWM registers if enabled. - */ - for (i = 1; i <= 3; i++) - { - if(PWMENABLE_FROM_REG(i, inp)) - data->pwm[i-1] = mtp008_read_value(client, - MTP008_REG_PWM_CTRL(i)); - else - data->pwm[i-1] = 255; - } - - /* - * Read the fan sensors. Skip 3 if PWM1 enabled. - */ - for (i = 1; i <= 3; i++) { - if(i == 3 && PWMENABLE_FROM_REG(1, inp)) { - data->fan[2] = 0; - data->fan_min[2] = 0; - } else { - data->fan[i-1] = mtp008_read_value(client, - MTP008_REG_FAN(i)); - data->fan_min[i-1] = mtp008_read_value(client, - MTP008_REG_FAN_MIN(i)); - } - } - - data->last_updated = jiffies; - data->valid = 1; - } - up(&data->update_lock); -} - -static void mtp008_getsensortype(struct mtp008_data *data, u8 inp) -{ - inp &= 0x0f; - data->sens[0] = (inp >> 3) + 2; /* 2 or 3 */ - data->sens[1] = ((inp >> 1) & 0x03) + 1; /* 1, 2 or 3 */ - data->sens[2] = (inp & 0x01) + 1; /* 1 or 2 */ -} - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -void mtp008_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int nr; - struct mtp008_data *data; - - nr = ctl_name - MTP008_SYSCTL_IN0; - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 2; - - break; - case SENSORS_PROC_REAL_READ: - mtp008_update_client(client); - - if((nr != 4 && nr != 5) || data->sens[nr - 3] == VOLTAGE) { - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - } else { - results[0] = 0; - results[1] = 0; - results[2] = 0; - } - - *nrels_mag = 3; - - break; - case SENSORS_PROC_REAL_WRITE: - if((nr != 4 && nr != 5) || data->sens[nr - 3] == VOLTAGE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0]); - mtp008_write_value(client, MTP008_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1]); - mtp008_write_value(client, MTP008_REG_IN_MAX(nr), - data->in_max[nr]); - } - } - } -} - -void mtp008_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int nr; - struct mtp008_data *data; - - nr = ctl_name - MTP008_SYSCTL_FAN1; - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 0; - - break; - case SENSORS_PROC_REAL_READ: - mtp008_update_client(client); - - results[0] = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - results[1] = FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr])); - - *nrels_mag = 2; - - break; - case SENSORS_PROC_REAL_WRITE: - if (*nrels_mag >= 1) { - data->fan_min[nr] = - FAN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr])); - mtp008_write_value(client, MTP008_REG_FAN_MIN(nr + 1), - data->fan_min[nr]); - } - } -} - -void mtp008_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct mtp008_data *data; - - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 1; - - break; - case SENSORS_PROC_REAL_READ: - mtp008_update_client(client); - - results[0] = TEMP_FROM_REG(data->temp_max); - results[1] = TEMP_FROM_REG(data->temp_min); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - - break; - case SENSORS_PROC_REAL_WRITE: - if (*nrels_mag >= 1) { - data->temp_max = TEMP_TO_REG(results[0]); - mtp008_write_value(client, MTP008_REG_TEMP_MAX, - data->temp_max); - } - if (*nrels_mag >= 2) { - data->temp_min = TEMP_TO_REG(results[1]); - mtp008_write_value(client, MTP008_REG_TEMP_MIN, - data->temp_min); - } - } -} - -void mtp008_temp_add(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int nr; - struct mtp008_data *data; - - nr = 3 + ctl_name - MTP008_SYSCTL_TEMP1; /* AIN4 or AIN5 */ - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 1; - - break; - case SENSORS_PROC_REAL_READ: - mtp008_update_client(client); - - if(data->sens[nr - 3] != VOLTAGE) { - results[0] = TEMP_FROM_REG(data->in_max[nr]); - results[1] = TEMP_FROM_REG(data->in_min[nr]); - results[2] = TEMP_FROM_REG(data->in[nr]); - } else { - results[0] = 0; - results[1] = 0; - results[2] = 0; - } - *nrels_mag = 3; - - break; - case SENSORS_PROC_REAL_WRITE: - if(data->sens[nr - 3] != VOLTAGE) { - if (*nrels_mag >= 1) { - data->in_max[nr] = TEMP_TO_REG(results[0]); - mtp008_write_value(client, - MTP008_REG_IN_MAX(nr), - data->in_max[nr]); - } - if (*nrels_mag >= 2) { - data->in_min[nr] = TEMP_TO_REG(results[1]); - mtp008_write_value(client, - MTP008_REG_IN_MIN(nr), - data->in_min[nr]); - } - } - } -} - -void mtp008_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct mtp008_data *data; - - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 2; - - break; - case SENSORS_PROC_REAL_READ: - mtp008_update_client(client); - - results[0] = VID_FROM_REG(data->vid); - - *nrels_mag = 1; - } -} - -void mtp008_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct mtp008_data *data; - u8 val; - - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 0; - - break; - case SENSORS_PROC_REAL_READ: - mtp008_update_client(client); - - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - results[2] = DIV_FROM_REG(data->fan_div[2]); - - *nrels_mag = 3; - - break; - case SENSORS_PROC_REAL_WRITE: - if (*nrels_mag >= 3) { - data->fan_div[2] = DIV_TO_REG(results[2]); - val = mtp008_read_value(client, MTP008_REG_PIN_CTRL1); - val = (val & 0x3f) | (data->fan_div[2] & 0x03) << 6; - mtp008_write_value(client, MTP008_REG_PIN_CTRL1, val); - } - if (*nrels_mag >= 1) { - val = mtp008_read_value(client, MTP008_REG_VID_FANDIV); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - val = (val & 0x3f) | - (data->fan_div[1] & 0x03) << 6; - } - data->fan_div[0] = DIV_TO_REG(results[0]); - val = (val & 0xcf) | (data->fan_div[0] & 0x03) << 4; - mtp008_write_value(client, MTP008_REG_VID_FANDIV, val); - } - } -} - -void mtp008_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct mtp008_data *data; - - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 0; - - break; - case SENSORS_PROC_REAL_READ: - mtp008_update_client(client); - - results[0] = ALARMS_FROM_REG(data->alarms); - - *nrels_mag = 1; - } -} - -void mtp008_beep(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct mtp008_data *data; - - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 0; - - break; - case SENSORS_PROC_REAL_READ: - mtp008_update_client(client); - - results[0] = BEEPS_FROM_REG(data->beeps); - - *nrels_mag = 1; - - break; - case SENSORS_PROC_REAL_WRITE: - if (*nrels_mag >= 1) { - data->beeps = BEEPS_TO_REG(results[0]) & 0xdf8f; - - mtp008_write_value(client, MTP008_REG_BEEP_CTRL1, - data->beeps & 0xff); - mtp008_write_value(client, MTP008_REG_BEEP_CTRL2, - data->beeps >> 8); - } - } -} - -void mtp008_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int nr; - struct mtp008_data *data; - - nr = ctl_name - MTP008_SYSCTL_PWM1; - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 0; - - break; - case SENSORS_PROC_REAL_READ: - mtp008_update_client(client); - - results[0] = PWM_FROM_REG(data->pwm[nr]); - results[1] = PWMENABLE_FROM_REG(nr + 1, data->pwmenable); - *nrels_mag = 2; - - break; - case SENSORS_PROC_REAL_WRITE: - if (*nrels_mag >= 1) { - if (*nrels_mag >= 2) { - if(results[1]) - data->pwmenable |= 0x10 << nr; - else - data->pwmenable &= ~(0x10 << nr); - mtp008_write_value(client, MTP008_REG_PIN_CTRL2, - data->pwmenable); - } - data->pwm[nr] = PWM_TO_REG(results[0]); - mtp008_write_value(client, MTP008_REG_PWM_CTRL(nr), - data->pwm[nr]); - } - } -} - -void mtp008_sens(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - const char *opts = ""; - int nr; - u8 tmp; - struct mtp008_data *data; - - nr = 1 + ctl_name - MTP008_SYSCTL_SENS1; - data = client->data; - - switch (operation) { - case SENSORS_PROC_REAL_INFO: - *nrels_mag = 0; - - break; - case SENSORS_PROC_REAL_READ: - results[0] = data->sens[nr - 1]; - - *nrels_mag = 1; - - break; - case SENSORS_PROC_REAL_WRITE: - if (*nrels_mag >= 1) { - tmp = mtp008_read_value(client, MTP008_REG_PIN_CTRL2); - - switch (nr) { - case 1: /* VT or PII */ - opts = "2 or 3"; - - switch (results[0]) { - case THERMISTOR: - mtp008_write_value( - client, MTP008_REG_PIN_CTRL2, - tmp & ~MTP008_CFG_VT1_PII); - data->sens[0] = 2; - return; - case PIIDIODE: - mtp008_write_value( - client, MTP008_REG_PIN_CTRL2, - tmp | MTP008_CFG_VT1_PII); - data->sens[0] = 3; - return; - } - - break; - case 2: /* AIN, VT or PII */ - tmp &= ~MTP008_CFG_VT2_MASK; - opts = "1, 2 or 3"; - - switch (results[0]) { - case VOLTAGE: - mtp008_write_value( - client, MTP008_REG_PIN_CTRL2, - tmp | MTP008_CFG_VT2_AIN); - data->sens[1] = 1; - return; - case THERMISTOR: - mtp008_write_value( - client, MTP008_REG_PIN_CTRL2, - tmp | MTP008_CFG_VT2_VT); - data->sens[1] = 2; - return; - case PIIDIODE: - mtp008_write_value( - client, MTP008_REG_PIN_CTRL2, - tmp | MTP008_CFG_VT2_PII); - data->sens[1] = 3; - return; - } - - break; - case 3: /* AIN or VT */ - opts = "1 or 2"; - - switch (results[0]) { - case VOLTAGE: - mtp008_write_value( - client, MTP008_REG_PIN_CTRL2, - tmp & ~MTP008_CFG_VT3_VT); - data->sens[2] = 1; - return; - case THERMISTOR: - mtp008_write_value( - client, MTP008_REG_PIN_CTRL2, - tmp | MTP008_CFG_VT3_VT); - data->sens[2] = 2; - return; - } - - break; - } - - printk("mtp008.o: Invalid sensor type %ld " - "for sensor %d; must be %s.\n", - results[0], nr, opts); - } - } -} - -static int __init sm_mtp008_init(void) -{ - printk("mtp008.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&mtp008_driver); -} - -static void __exit sm_mtp008_exit(void) -{ - i2c_del_driver(&mtp008_driver); -} - - - -MODULE_AUTHOR("Frodo Looijaard , " - "Philip Edelbrock , " - "and Kris Van Hees "); -MODULE_DESCRIPTION("MTP008 driver"); - -module_init(sm_mtp008_init); -module_exit(sm_mtp008_exit); diff --git a/kernel/chips/pc87360.c b/kernel/chips/pc87360.c deleted file mode 100644 index 19f1d279..00000000 --- a/kernel/chips/pc87360.c +++ /dev/null @@ -1,1350 +0,0 @@ -/* - * pc87360.c - Part of lm_sensors, Linux kernel modules - * for hardware monitoring - * Copyright (C) 2004 Jean Delvare - * - * Copied from smsc47m1.c: - * Copyright (C) 2002 Mark D. Studebaker - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Supports the following chips: - * - * Chip #vin #fan #pwm #temp devid - * PC87360 - 2 2 - 0xE1 - * PC87363 - 2 2 - 0xE8 - * PC87364 - 3 3 - 0xE4 - * PC87365 11 3 3 2 0xE5 - * PC87366 11 3 3 3-4 0xE9 - * - * This driver assumes that no more than one chip is present, and the - * standard Super-I/O address is used (0x2E/0x2F). - */ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" - -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; -static struct i2c_force_data forces[] = {{NULL}}; -static u8 devid; -static unsigned int extra_isa[] = { 0x0000, 0x0000, 0x0000 }; -static u8 confreg[4]; - -enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 }; -static struct i2c_address_data addr_data = { - .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, - .normal_isa = normal_isa, - .normal_isa_range = normal_isa_range, - .probe = normal_i2c, /* cheat */ - .probe_range = normal_i2c_range, /* cheat */ - .ignore = normal_i2c, /* cheat */ - .ignore_range = normal_i2c_range, /* cheat */ - .forces = forces, -}; - -static int init = 1; -MODULE_PARM(init, "i"); -MODULE_PARM_DESC(init, - "Chip initialization level:\n" - " 0: None\n" - "*1: Forcibly enable internal voltage and temperature channels, except in9\n" - " 2: Forcibly enable all voltage and temperature channels, except in9\n" - " 3: Forcibly enable all voltage and temperature channels, including in9"); - -/* - * Super-I/O registers and operations - */ - -#define DEV 0x07 /* Register: Logical device select */ -#define DEVID 0x20 /* Register: Device ID */ -#define ACT 0x30 /* Register: Device activation */ -#define BASE 0x60 /* Register: Base address */ - -#define FSCM 0x09 /* Logical device: fans */ -#define VLM 0x0d /* Logical device: voltages */ -#define TMS 0x0e /* Logical device: temperatures */ -static const u8 logdev[3] = { FSCM, VLM, TMS }; - -#define LD_FAN 0 -#define LD_IN 1 -#define LD_TEMP 2 - -static inline void superio_outb(int sioaddr, int reg, int val) -{ - outb(reg, sioaddr); - outb(val, sioaddr+1); -} - -static inline int superio_inb(int sioaddr, int reg) -{ - outb(reg, sioaddr); - return inb(sioaddr+1); -} - -static inline void superio_exit(int sioaddr) -{ - outb(0x02, sioaddr); - outb(0x02, sioaddr+1); -} - -/* - * Logical devices - */ - -#define PC87360_EXTENT 0x10 -#define PC87365_REG_BANK 0x09 -#define NO_BANK 0xff - -/* - * Fan registers and conversions - */ - -/* nr has to be 0 or 1 (PC87360/87363) or 2 (PC87364/87365/87366) */ -#define PC87360_REG_PRESCALE(nr) (0x00 + 2 * (nr)) -#define PC87360_REG_PWM(nr) (0x01 + 2 * (nr)) -#define PC87360_REG_FAN_MIN(nr) (0x06 + 3 * (nr)) -#define PC87360_REG_FAN(nr) (0x07 + 3 * (nr)) -#define PC87360_REG_FAN_STATUS(nr) (0x08 + 3 * (nr)) - -#define FAN_FROM_REG(val,div) ((val)==0?0: \ - 480000/((val)*(div))) -#define FAN_TO_REG(val,div) ((val)<=100?0: \ - 480000/((val)*(div))) -#define FAN_DIV_FROM_REG(val) (1 << ((val >> 5) & 0x03)) -#define FAN_DIV_TO_REG(val) ((val)==8?0x60:(val)==4?0x40: \ - (val)==1?0x00:0x20) -#define FAN_STATUS_FROM_REG(val) ((val) & 0x07) - -#define FAN_CONFIG_MONITOR(val,nr) (((val) >> (2 + nr * 3)) & 1) -#define FAN_CONFIG_CONTROL(val,nr) (((val) >> (3 + nr * 3)) & 1) -#define FAN_CONFIG_INVERT(val,nr) (((val) >> (4 + nr * 3)) & 1) - -#define PWM_FROM_REG(val,inv) ((inv) ? 255 - (val) : (val)) -static inline u8 PWM_TO_REG(int val, int inv) -{ - if (inv) - val = 255 - val; - if (val < 0) - return 0; - if (val > 255) - return 255; - return val; -} - -/* - * Voltage registers and conversions - */ - -#define PC87365_REG_IN_CONVRATE 0x07 -#define PC87365_REG_IN_CONFIG 0x08 -#define PC87365_REG_IN 0x0B -#define PC87365_REG_IN_MIN 0x0D -#define PC87365_REG_IN_MAX 0x0C -#define PC87365_REG_IN_STATUS 0x0A -#define PC87365_REG_IN_ALARMS1 0x00 -#define PC87365_REG_IN_ALARMS2 0x01 -#define PC87365_REG_VID 0x06 - -#define IN_FROM_REG(val,ref) (((val) * (ref) + 128) / 256) -#define IN_TO_REG(val,ref) ((val)<0 ? 0 : \ - (val)*256>=(ref)*255 ? 255: \ - ((val) * 256 + (ref) / 2) / (ref)) - -/* - * Temperature registers and conversions - */ - -#define PC87365_REG_TEMP_CONFIG 0x08 -#define PC87365_REG_TEMP 0x0B -#define PC87365_REG_TEMP_MIN 0x0D -#define PC87365_REG_TEMP_MAX 0x0C -#define PC87365_REG_TEMP_CRIT 0x0E -#define PC87365_REG_TEMP_STATUS 0x0A -#define PC87365_REG_TEMP_ALARMS 0x00 - -#define TEMP_FROM_REG(val) ((val)&0x80 ? (val) - 0x100 : (val)) -#define TEMP_TO_REG(val) ((val)<-55 ? 201 : (val)>127 ? 0x7F : \ - (val)<0 ? (val) + 0x100 : (val)) - -struct pc87360_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - int address[3]; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 fannr, innr, tempnr; - - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 fan_status[3]; /* Register value */ - u8 pwm[3]; /* Register value */ - u16 fan_conf; /* Configuration register values, combined */ - - u16 in_vref; /* 10mV/bit */ - u8 in[14]; /* Register value */ - u8 in_min[14]; /* Register value */ - u8 in_max[14]; /* Register value */ - u8 in_crit[3]; /* Register value */ - u8 in_status[14]; /* Register value */ - u16 in_alarms; /* Register values, combined, masked */ - u8 vid_conf; /* Configuration register value */ - u8 vrm; - u8 vid; /* Register value */ - - u8 temp[3]; /* Register value */ - u8 temp_min[3]; /* Register value */ - u8 temp_max[3]; /* Register value */ - u8 temp_crit[3]; /* Register value */ - u8 temp_status[3]; /* Register value */ - u8 temp_alarms; /* Register value, masked */ -}; - - -static int pc87360_attach_adapter(struct i2c_adapter *adapter); -static int pc87360_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int pc87360_detach_client(struct i2c_client *client); - -static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg); -static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg, u8 value); -static void pc87360_init_client(struct i2c_client *client, int use_thermistors); -static void pc87360_update_client(struct i2c_client *client); - - -void pc87365_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); - -static void pc87360_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pc87360_fan_status(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pc87360_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pc87360_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -void pc87365_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -void pc87365_in_status(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -void pc87365_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -void pc87365_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); - -void pc87365_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -void pc87365_temp_status(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); - -static struct i2c_driver pc87360_driver = { - .name = "PC8736x hardware monitor", - .flags = I2C_DF_NOTIFY, - .attach_adapter = pc87360_attach_adapter, - .detach_client = pc87360_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define PC87365_SYSCTL_ALARMS 100 /* bit field */ - -#define PC87360_SYSCTL_FAN1 1101 /* Rotations/min */ -#define PC87360_SYSCTL_FAN2 1102 -#define PC87360_SYSCTL_FAN3 1103 /* not for PC87360/PC87363 */ -#define PC87360_SYSCTL_FAN_DIV 1201 /* 1, 2, 4 or 8 */ -#define PC87360_SYSCTL_FAN1_STATUS 1301 /* bit field */ -#define PC87360_SYSCTL_FAN2_STATUS 1302 -#define PC87360_SYSCTL_FAN3_STATUS 1303 /* not for PC87360/PC87363 */ -#define PC87360_SYSCTL_PWM1 1401 /* 0-255 */ -#define PC87360_SYSCTL_PWM2 1402 -#define PC87360_SYSCTL_PWM3 1403 /* not for PC87360/PC87363 */ - -#define PC87360_STATUS_FAN_READY 0x01 -#define PC87360_STATUS_FAN_LOW 0x02 -#define PC87360_STATUS_FAN_OVERFLOW 0x04 - -#define PC87365_SYSCTL_IN0 2100 /* mV */ -#define PC87365_SYSCTL_IN1 2101 -#define PC87365_SYSCTL_IN2 2102 -#define PC87365_SYSCTL_IN3 2103 -#define PC87365_SYSCTL_IN4 2104 -#define PC87365_SYSCTL_IN5 2105 -#define PC87365_SYSCTL_IN6 2106 -#define PC87365_SYSCTL_IN7 2107 -#define PC87365_SYSCTL_IN8 2108 -#define PC87365_SYSCTL_IN9 2109 -#define PC87365_SYSCTL_IN10 2110 -#define PC87365_SYSCTL_TEMP4 2111 /* not for PC87365 */ -#define PC87365_SYSCTL_TEMP5 2112 /* not for PC87365 */ -#define PC87365_SYSCTL_TEMP6 2113 /* not for PC87365 */ -#define PC87365_SYSCTL_IN0_STATUS 2300 /* bit field */ -#define PC87365_SYSCTL_IN1_STATUS 2301 -#define PC87365_SYSCTL_IN2_STATUS 2302 -#define PC87365_SYSCTL_IN3_STATUS 2303 -#define PC87365_SYSCTL_IN4_STATUS 2304 -#define PC87365_SYSCTL_IN5_STATUS 2305 -#define PC87365_SYSCTL_IN6_STATUS 2306 -#define PC87365_SYSCTL_IN7_STATUS 2307 -#define PC87365_SYSCTL_IN8_STATUS 2308 -#define PC87365_SYSCTL_IN9_STATUS 2309 -#define PC87365_SYSCTL_IN10_STATUS 2310 -#define PC87365_SYSCTL_TEMP4_STATUS 2311 /* not for PC87365 */ -#define PC87365_SYSCTL_TEMP5_STATUS 2312 /* not for PC87365 */ -#define PC87365_SYSCTL_TEMP6_STATUS 2313 /* not for PC87365 */ - -#define PC87365_SYSCTL_VID 2400 -#define PC87365_SYSCTL_VRM 2401 - -#define PC87365_STATUS_IN_MIN 0x02 -#define PC87365_STATUS_IN_MAX 0x04 - -#define PC87365_SYSCTL_TEMP1 3101 /* degrees Celsius */ -#define PC87365_SYSCTL_TEMP2 3102 -#define PC87365_SYSCTL_TEMP3 3103 /* not for PC87365 */ -#define PC87365_SYSCTL_TEMP1_STATUS 3301 /* bit field */ -#define PC87365_SYSCTL_TEMP2_STATUS 3302 -#define PC87365_SYSCTL_TEMP3_STATUS 3303 /* not for PC87365 */ - -#define PC87365_STATUS_TEMP_MIN 0x02 -#define PC87365_STATUS_TEMP_MAX 0x04 -#define PC87365_STATUS_TEMP_CRIT 0x08 -#define PC87365_STATUS_TEMP_OPEN 0x40 - -/* -- SENSORS SYSCTL END -- */ - -static ctl_table pc87360_dir_table_template[] = { /* PC87363 and PC87364 too */ - {PC87360_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan}, - {PC87360_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan}, - {PC87360_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan}, - {PC87360_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_div}, - {PC87360_SYSCTL_FAN1_STATUS, "fan1_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status}, - {PC87360_SYSCTL_FAN2_STATUS, "fan2_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status}, - {PC87360_SYSCTL_FAN3_STATUS, "fan3_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status}, - {PC87360_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm}, - {PC87360_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm}, - {PC87360_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm}, - {0} -}; - -static ctl_table pc87365_dir_table_template[] = { /* PC87366 too */ - {PC87365_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_alarms}, - {PC87360_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan}, - {PC87360_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan}, - {PC87360_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan}, - {PC87360_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_div}, - {PC87360_SYSCTL_FAN1_STATUS, "fan1_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status}, - {PC87360_SYSCTL_FAN2_STATUS, "fan2_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status}, - {PC87360_SYSCTL_FAN3_STATUS, "fan3_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_fan_status}, - {PC87360_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm}, - {PC87360_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm}, - {PC87360_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87360_pwm}, - {PC87365_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN9, "in9", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN10, "in10", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_IN0_STATUS, "in0_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN1_STATUS, "in1_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN2_STATUS, "in2_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN3_STATUS, "in3_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN4_STATUS, "in4_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN5_STATUS, "in5_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN6_STATUS, "in6_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN7_STATUS, "in7_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN8_STATUS, "in8_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN9_STATUS, "in9_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_IN10_STATUS, "in10_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp}, - {PC87365_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp}, - {PC87365_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp}, - {PC87365_SYSCTL_TEMP4, "temp4", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_TEMP5, "temp5", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_TEMP6, "temp6", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in}, - {PC87365_SYSCTL_TEMP1_STATUS, "temp1_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp_status}, - {PC87365_SYSCTL_TEMP2_STATUS, "temp2_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp_status}, - {PC87365_SYSCTL_TEMP3_STATUS, "temp3_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_temp_status}, - {PC87365_SYSCTL_TEMP4_STATUS, "temp4_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_TEMP5_STATUS, "temp5_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_TEMP6_STATUS, "temp6_status", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, - {PC87365_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_vid}, - {PC87365_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_vrm}, - {0} -}; - -static int pc87360_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, pc87360_detect); -} - -static int __init pc87360_find(int sioaddr, u8 *devid, int *address) -{ - u16 val; - int i; - int nrdev; /* logical device count */ - - /* No superio_enter */ - - /* Identify device */ - val = superio_inb(sioaddr, DEVID); - switch (val) { - case 0xE1: /* PC87360 */ - case 0xE8: /* PC87363 */ - case 0xE4: /* PC87364 */ - nrdev = 1; - break; - case 0xE5: /* PC87365 */ - case 0xE9: /* PC87366 */ - nrdev = 3; - break; - default: - superio_exit(sioaddr); - return -ENODEV; - } - /* Remember the device id */ - *devid = val; - - for (i = 0; i < nrdev; i++) { - /* select logical device */ - superio_outb(sioaddr, DEV, logdev[i]); - - val = superio_inb(sioaddr, ACT); - if (!(val & 0x01)) { - printk(KERN_INFO "pc87360.o: Device 0x%02x not " - "activated\n", logdev[i]); - continue; - } - - val = (superio_inb(sioaddr, BASE) << 8) - | superio_inb(sioaddr, BASE + 1); - if (!val) { - printk(KERN_INFO "pc87360.o: Base address not set for " - "device 0x%02x\n", logdev[i]); - continue; - } - - address[i] = val; - - if (i==0) { /* Fans */ - confreg[0] = superio_inb(sioaddr, 0xF0); - confreg[1] = superio_inb(sioaddr, 0xF1); - -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Fan 1: mon=%d " - "ctrl=%d inv=%d\n", (confreg[0]>>2)&1, - (confreg[0]>>3)&1, (confreg[0]>>4)&1); - printk(KERN_DEBUG "pc87360.o: Fan 2: mon=%d " - "ctrl=%d inv=%d\n", (confreg[0]>>5)&1, - (confreg[0]>>6)&1, (confreg[0]>>7)&1); - printk(KERN_DEBUG "pc87360.o: Fan 3: mon=%d " - "ctrl=%d inv=%d\n", confreg[1]&1, - (confreg[1]>>1)&1, (confreg[1]>>2)&1); -#endif - } else if (i==1) { /* Voltages */ - /* Are we using thermistors? */ - if (*devid == 0xE9) { /* PC87366 */ - /* These registers are not logical-device - specific, just that we won't need them if - we don't use the VLM device */ - confreg[2] = superio_inb(sioaddr, 0x2B); - confreg[3] = superio_inb(sioaddr, 0x25); - - if (confreg[2] & 0x40) { - printk(KERN_INFO "pc87360.o: Using " - "thermistors for temperature " - "monitoring\n"); - } - if (confreg[3] & 0xE0) { - printk(KERN_INFO "pc87360.o: VID " - "inputs routed (mode %u)\n", - confreg[3] >> 5); - } - } - } - } - - superio_exit(sioaddr); - return 0; -} - -/* We don't really care about the address. - Read from extra_isa instead. */ -int pc87360_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct pc87360_data *data; - int err = 0; - const char *type_name = "pc87360"; - const char *client_name = "PC8736x chip"; - ctl_table *template = pc87360_dir_table_template; - int use_thermistors = 0; - - if (!i2c_is_isa_adapter(adapter)) { - return 0; - } - - for (i = 0; i < 3; i++) { - if (extra_isa[i] - && check_region(extra_isa[i], PC87360_EXTENT)) { - printk(KERN_ERR "pc87360.o: Region 0x%x-0x%x already " - "in use!\n", extra_isa[i], - extra_isa[i]+PC87360_EXTENT-1); - return -ENODEV; - } - } - - if (!(data = kmalloc(sizeof(struct pc87360_data), GFP_KERNEL))) { - return -ENOMEM; - } - memset(data, 0x00, sizeof(struct pc87360_data)); - - new_client = &data->client; - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &pc87360_driver; - new_client->flags = 0; - - data->fannr = 2; - data->innr = 0; - data->tempnr = 0; - - switch (devid) { - case 0xe8: - type_name = "pc87363"; - break; - case 0xe4: - type_name = "pc87364"; - data->fannr = 3; - break; - case 0xe5: - type_name = "pc87365"; - template = pc87365_dir_table_template; - data->fannr = extra_isa[0] ? 3 : 0; - data->innr = extra_isa[1] ? 11 : 0; - data->tempnr = extra_isa[2] ? 2 : 0; - break; - case 0xe9: - type_name = "pc87366"; - template = pc87365_dir_table_template; - data->fannr = extra_isa[0] ? 3 : 0; - data->innr = extra_isa[1] ? 14 : 0; - data->tempnr = extra_isa[2] ? 3 : 0; - break; - } - - /* Retrieve the fans configuration from Super-I/O space */ - if (data->fannr) - data->fan_conf = confreg[0] | (confreg[1] << 8); - - for (i = 0; i < 3; i++) { - if ((data->address[i] = extra_isa[i])) { - request_region(extra_isa[i], PC87360_EXTENT, "pc87360"); - } - } - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - if ((err = i2c_attach_client(new_client))) - goto ERROR1; - - /* Use the correct reference voltage - Unless both the VLM and the TMS logical devices agree to - use an external Vref, the internal one is used. */ - if (data->innr) { - i = pc87360_read_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONFIG); - if (data->tempnr) { - i &= pc87360_read_value(data, LD_TEMP, NO_BANK, - PC87365_REG_TEMP_CONFIG); - } - data->in_vref = (i&0x02) ? 3025 : 2966; -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Using %s reference voltage\n", - (i&0x02) ? "external" : "internal"); -#endif - - data->vid_conf = confreg[3]; - data->vrm = 90; - } - - /* Fan clock dividers may be needed before any data is read */ - for (i = 0; i < data->fannr; i++) { - if (FAN_CONFIG_MONITOR(data->fan_conf, i)) - data->fan_status[i] = pc87360_read_value(data, - LD_FAN, NO_BANK, - PC87360_REG_FAN_STATUS(i)); - } - - if (init > 0) { - if (devid == 0xe9 && data->address[1]) /* PC87366 */ - use_thermistors = confreg[2] & 0x40; - - pc87360_init_client(new_client, use_thermistors); - } - - if ((i = i2c_register_entry((struct i2c_client *) new_client, - type_name, template, THIS_MODULE)) < 0) { - err = i; - goto ERROR2; - } - data->sysctl_id = i; - - return 0; - -ERROR2: - i2c_detach_client(new_client); -ERROR1: - for (i = 0; i < 3; i++) { - if (data->address[i]) { - release_region(data->address[i], PC87360_EXTENT); - } - } - kfree(data); - return err; -} - -static int pc87360_detach_client(struct i2c_client *client) -{ - struct pc87360_data *data = client->data; - int i, err; - - i2c_deregister_entry(data->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR "pc87360.o: Client deregistration failed, " - "client not detached.\n"); - return err; - } - - for (i = 0; i < 3; i++) { - if (data->address[i]) { - release_region(data->address[i], PC87360_EXTENT); - } - } - kfree(client->data); - - return 0; -} - -/* ldi is the logical device index - bank is for voltages and temperatures only */ -static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg) -{ - int res; - - down(&(data->lock)); - if (bank != NO_BANK) { - outb_p(bank, data->address[ldi] + PC87365_REG_BANK); - } - res = inb_p(data->address[ldi] + reg); - up(&(data->lock)); - return res; -} - -static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, - u8 reg, u8 value) -{ - down(&(data->lock)); - if (bank != NO_BANK) { - outb_p(bank, data->address[ldi] + PC87365_REG_BANK); - } - outb_p(value, data->address[ldi] + reg); - up(&(data->lock)); -} - -static void pc87360_init_client(struct i2c_client *client, int use_thermistors) -{ - struct pc87360_data *data = client->data; - int i, nr; - const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 }; - const u8 init_temp[3] = { 2, 2, 1 }; - u8 reg; - - if (init >= 2 && data->innr) { - reg = pc87360_read_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONVRATE); - printk(KERN_INFO "pc87360.o: VLM conversion set to " - "1s period, 160us delay\n"); - pc87360_write_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONVRATE, - (reg & 0xC0) | 0x11); - } - - nr = data->innr < 11 ? data->innr : 11; - for (i=0; i= init_in[i]) { - /* Forcibly enable voltage channel */ - reg = pc87360_read_value(data, LD_IN, i, - PC87365_REG_IN_STATUS); - if (!(reg & 0x01)) { -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Forcibly " - "enabling in%d\n", i); -#endif - pc87360_write_value(data, LD_IN, i, - PC87365_REG_IN_STATUS, - (reg & 0x68) | 0x87); - } - } - } - - /* We can't blindly trust the Super-I/O space configuration bit, - most BIOS won't set it properly */ - for (i=11; iinnr; i++) { - reg = pc87360_read_value(data, LD_IN, i, - PC87365_REG_TEMP_STATUS); - use_thermistors = use_thermistors || (reg & 0x01); - } - - i = use_thermistors ? 2 : 0; - for (; itempnr; i++) { - if (init >= init_temp[i]) { - /* Forcibly enable temperature channel */ - reg = pc87360_read_value(data, LD_TEMP, i, - PC87365_REG_TEMP_STATUS); - if (!(reg & 0x01)) { -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Forcibly " - "enabling temp%d\n", i+1); -#endif - pc87360_write_value(data, LD_TEMP, i, - PC87365_REG_TEMP_STATUS, - 0xCF); - } - } - } - - if (use_thermistors) { - for (i=11; iinnr; i++) { - if (init >= init_in[i]) { - /* The pin may already be used by thermal - diodes */ - reg = pc87360_read_value(data, LD_TEMP, (i-11)/2, - PC87365_REG_TEMP_STATUS); - if (reg & 0x01) { -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Skipping " - "temp%d, pin already in use by " - "temp%d\n", i-7, (i-11)/2); -#endif - continue; - } - - /* Forcibly enable thermistor channel */ - reg = pc87360_read_value(data, LD_IN, i, - PC87365_REG_IN_STATUS); - if (!(reg & 0x01)) { -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Forcibly " - "enabling temp%d\n", i-7); -#endif - pc87360_write_value(data, LD_IN, i, - PC87365_REG_TEMP_STATUS, - (reg & 0x60) | 0x8F); - } - } - } - } - - if (data->innr) { - reg = pc87360_read_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONFIG); - if (reg & 0x01) { -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Forcibly " - "enabling monitoring (VLM)\n"); -#endif - pc87360_write_value(data, LD_IN, NO_BANK, - PC87365_REG_IN_CONFIG, - reg & 0xFE); - } - } - - if (data->tempnr) { - reg = pc87360_read_value(data, LD_TEMP, NO_BANK, - PC87365_REG_TEMP_CONFIG); - if (reg & 0x01) { -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Forcibly " - "enabling monitoring (TMS)\n"); -#endif - pc87360_write_value(data, LD_TEMP, NO_BANK, - PC87365_REG_TEMP_CONFIG, - reg & 0xFE); - } - - if (init >= 2) { - /* Chip config as documented by National Semi. */ - pc87360_write_value(data, LD_TEMP, 0xF, 0xA, 0x08); - /* We voluntarily omit the bank here, in case the - sequence itself matters. It shouldn't be a problem, - since nobody else is supposed to access the - device at that point. */ - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xB, 0x04); - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xC, 0x35); - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xD, 0x05); - pc87360_write_value(data, LD_TEMP, NO_BANK, 0xE, 0x05); - } - } -} - -static void pc87360_autodiv(struct pc87360_data *data, int nr) -{ - u8 old_min = data->fan_min[nr]; - - /* Increase clock divider if needed and possible */ - if ((data->fan_status[nr] & 0x04) /* overflow flag */ - || (data->fan[nr] >= 224)) { /* next to overflow */ - if ((data->fan_status[nr] & 0x60) != 0x60) { - data->fan_status[nr] += 0x20; - data->fan_min[nr] >>= 1; - data->fan[nr] >>= 1; -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Increasing " - "clock divider to %d for fan %d\n", - FAN_DIV_FROM_REG(data->fan_status[nr]), - nr+1); -#endif - } - } else { - /* Decrease clock divider if possible */ - while (!(data->fan_min[nr] & 0x80) /* fan min "nails" divider */ - && data->fan[nr] < 85 /* bad accuracy */ - && (data->fan_status[nr] & 0x60) != 0x00) { - data->fan_status[nr] -= 0x20; - data->fan_min[nr] <<= 1; - data->fan[nr] <<= 1; -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Decreasing " - "clock divider to %d for fan %d\n", - FAN_DIV_FROM_REG(data->fan_status[nr]), - nr+1); -#endif - } - } - - /* Write new fan min if it changed */ - if (old_min != data->fan_min[nr]) { - pc87360_write_value(data, LD_FAN, NO_BANK, - PC87360_REG_FAN_MIN(nr), - data->fan_min[nr]); - } -} - -static void pc87360_update_client(struct i2c_client *client) -{ - struct pc87360_data *data = client->data; - u8 i; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ * 2) || - (jiffies < data->last_updated) || !data->valid) { -#ifdef DEBUG - printk(KERN_DEBUG "pc87360.o: Data update\n"); -#endif - - /* Fans */ - for (i = 0; i < data->fannr; i++) { - if (FAN_CONFIG_MONITOR(data->fan_conf, i)) { - data->fan_status[i] = pc87360_read_value(data, - LD_FAN, NO_BANK, - PC87360_REG_FAN_STATUS(i)); - data->fan[i] = pc87360_read_value(data, LD_FAN, - NO_BANK, PC87360_REG_FAN(i)); - data->fan_min[i] = pc87360_read_value(data, - LD_FAN, NO_BANK, - PC87360_REG_FAN_MIN(i)); - /* Change clock divider if needed */ - pc87360_autodiv(data, i); - /* Clear bits and write new divider */ - pc87360_write_value(data, LD_FAN, NO_BANK, - PC87360_REG_FAN_STATUS(i), - data->fan_status[i]); - } - data->pwm[i] = pc87360_read_value(data, LD_FAN, - NO_BANK, PC87360_REG_PWM(i)); - } - - /* Voltages */ - for (i = 0; i < data->innr; i++) { - data->in_status[i] = pc87360_read_value(data, LD_IN, i, - PC87365_REG_IN_STATUS); - /* Clear bits */ - pc87360_write_value(data, LD_IN, i, - PC87365_REG_IN_STATUS, - data->in_status[i]); - if ((data->in_status[i] & 0x81) == 0x81) { - data->in[i] = pc87360_read_value(data, LD_IN, - i, PC87365_REG_IN); - } - if (data->in_status[i] & 0x01) { - data->in_min[i] = pc87360_read_value(data, - LD_IN, i, - PC87365_REG_IN_MIN); - data->in_max[i] = pc87360_read_value(data, - LD_IN, i, - PC87365_REG_IN_MAX); - if (i >= 11) - data->in_crit[i-11] = - pc87360_read_value(data, LD_IN, - i, PC87365_REG_TEMP_CRIT); - } - } - if (data->innr) { - data->in_alarms = pc87360_read_value(data, LD_IN, - NO_BANK, PC87365_REG_IN_ALARMS1) - | ((pc87360_read_value(data, LD_IN, - NO_BANK, PC87365_REG_IN_ALARMS2) - & 0x07) << 8); - data->vid = (data->vid_conf & 0xE0) ? - pc87360_read_value(data, LD_IN, - NO_BANK, PC87365_REG_VID) : 0x1F; - } - - /* Temperatures */ - for (i = 0; i < data->tempnr; i++) { - data->temp_status[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_STATUS); - /* Clear bits */ - pc87360_write_value(data, LD_TEMP, i, - PC87365_REG_TEMP_STATUS, - data->temp_status[i]); - if ((data->temp_status[i] & 0x81) == 0x81) { - data->temp[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP); - } - if (data->temp_status[i] & 0x01) { - data->temp_min[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_MIN); - data->temp_max[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_MAX); - data->temp_crit[i] = pc87360_read_value(data, - LD_TEMP, i, - PC87365_REG_TEMP_CRIT); - } - } - if (data->tempnr) { - data->temp_alarms = pc87360_read_value(data, LD_TEMP, - NO_BANK, PC87365_REG_TEMP_ALARMS) - & 0x3F; - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void pc87365_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - results[0] = data->in_alarms; - results[1] = data->temp_alarms; - *nrels_mag = 2; - } -} - -void pc87360_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - int nr = ctl_name - PC87360_SYSCTL_FAN1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr], - FAN_DIV_FROM_REG(data->fan_status[nr])); - results[1] = FAN_FROM_REG(data->fan[nr], - FAN_DIV_FROM_REG(data->fan_status[nr])); - *nrels_mag = 2; - } - /* We ignore National's recommendation */ - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (nr >= data->fannr) - return; - if (*nrels_mag >= 1) { - int fan_min = FAN_TO_REG(results[0], - FAN_DIV_FROM_REG(data->fan_status[nr])); - /* If it wouldn't fit, change clock divisor */ - while (fan_min > 255 - && (data->fan_status[nr] & 0x60) != 0x60) { - fan_min >>= 1; - data->fan[nr] >>= 1; - data->fan_status[nr] += 0x20; - } - data->fan_min[nr] = fan_min > 255 ? 255 : fan_min; - pc87360_write_value(data, LD_FAN, NO_BANK, - PC87360_REG_FAN_MIN(nr), - data->fan_min[nr]); - /* Write new divider, preserve alarm bits */ - pc87360_write_value(data, LD_FAN, NO_BANK, - PC87360_REG_FAN_STATUS(nr), - data->fan_status[nr] & 0xF9); - } - } -} - -void pc87360_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - int i; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - for (i = 0; i < data->fannr; i++) { - results[i] = FAN_DIV_FROM_REG(data->fan_status[i]); - } - for (; i < 3; i++) { - results[i] = 0; - } - *nrels_mag = 3; - } -} - -void pc87360_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - int nr = ctl_name - PC87360_SYSCTL_PWM1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - results[0] = PWM_FROM_REG(data->pwm[nr], - FAN_CONFIG_INVERT(data->fan_conf, nr)); - results[1] = FAN_CONFIG_CONTROL(data->fan_conf, nr); - *nrels_mag = 2; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (nr >= data->fannr) - return; - if (*nrels_mag >= 1) { - data->pwm[nr] = PWM_TO_REG(results[0], - FAN_CONFIG_INVERT(data->fan_conf, nr)); - pc87360_write_value(data, LD_FAN, NO_BANK, - PC87360_REG_PWM(nr), - data->pwm[nr]); - } - } -} - -void pc87360_fan_status(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - int nr = ctl_name - PC87360_SYSCTL_FAN1_STATUS; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - results[0] = FAN_STATUS_FROM_REG(data->fan_status[nr]); - *nrels_mag = 1; - } -} - -void pc87365_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - int nr = ctl_name - PC87365_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr], data->in_vref); - results[1] = IN_FROM_REG(data->in_max[nr], data->in_vref); - if (nr < 11) { - *nrels_mag = 3; - } else { - results[2] = IN_FROM_REG(data->in_crit[nr-11], - data->in_vref); - *nrels_mag = 4; - } - results[(*nrels_mag)-1] = IN_FROM_REG(data->in[nr], - data->in_vref); - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0], - data->in_vref); - pc87360_write_value(data, LD_IN, nr, - PC87365_REG_IN_MIN, - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1], - data->in_vref); - pc87360_write_value(data, LD_IN, nr, - PC87365_REG_IN_MAX, - data->in_max[nr]); - } - if (*nrels_mag >= 3 && nr >= 11) { - data->in_crit[nr-11] = IN_TO_REG(results[2], - data->in_vref); - pc87360_write_value(data, LD_IN, nr, - PC87365_REG_TEMP_CRIT, - data->in_crit[nr-11]); - } - } -} - -void pc87365_in_status(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - int nr = ctl_name - PC87365_SYSCTL_IN0_STATUS; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - results[0] = data->in_status[nr]; - *nrels_mag = 1; - } -} - -void pc87365_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - results[0] = vid_from_reg(data->vid & 0x1f, data->vrm); - *nrels_mag = 1; - } -} - -void pc87365_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) - data->vrm = results[0]; - } -} - -void pc87365_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - int nr = ctl_name - PC87365_SYSCTL_TEMP1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_max[nr]); - results[1] = TEMP_FROM_REG(data->temp_min[nr]); - results[2] = TEMP_FROM_REG(data->temp_crit[nr]); - results[3] = TEMP_FROM_REG(data->temp[nr]); - *nrels_mag = 4; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (nr >= data->tempnr) - return; - if (*nrels_mag >= 1) { - data->temp_max[nr] = TEMP_TO_REG(results[0]); - pc87360_write_value(data, LD_TEMP, nr, - PC87365_REG_TEMP_MAX, - data->temp_max[nr]); - } - if (*nrels_mag >= 2) { - data->temp_min[nr] = TEMP_TO_REG(results[1]); - pc87360_write_value(data, LD_TEMP, nr, - PC87365_REG_TEMP_MIN, - data->temp_min[nr]); - } - if (*nrels_mag >= 3) { - data->temp_crit[nr] = TEMP_TO_REG(results[2]); - pc87360_write_value(data, LD_TEMP, nr, - PC87365_REG_TEMP_CRIT, - data->temp_crit[nr]); - } - } -} - -void pc87365_temp_status(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pc87360_data *data = client->data; - int nr = ctl_name - PC87365_SYSCTL_TEMP1_STATUS; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pc87360_update_client(client); - results[0] = data->temp_status[nr]; - *nrels_mag = 1; - } -} - - -static int __init pc87360_init(void) -{ - int i; - - printk(KERN_INFO "pc87360.o version %s (%s)\n", LM_VERSION, LM_DATE); - - if (pc87360_find(0x2e, &devid, extra_isa) - && pc87360_find(0x4e, &devid, extra_isa)) { - printk(KERN_WARNING "pc87360.o: PC8736x not detected, " - "module not inserted.\n"); - return -ENODEV; - } - - /* Arbitrarily pick one of the addresses */ - for (i = 0; i < 3; i++) { - if (extra_isa[i] != 0x0000) { - normal_isa[0] = extra_isa[i]; - break; - } - } - - if (normal_isa[0] == 0x0000) { - printk(KERN_WARNING "pc87360.o: No active logical device, " - "module not inserted.\n"); - return -ENODEV; - - } - - return i2c_add_driver(&pc87360_driver); -} - -static void __exit pc87360_exit(void) -{ - i2c_del_driver(&pc87360_driver); -} - - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("PC8736x hardware monitor"); -MODULE_LICENSE("GPL"); - -module_init(pc87360_init); -module_exit(pc87360_exit); diff --git a/kernel/chips/pca9540.c b/kernel/chips/pca9540.c deleted file mode 100644 index 8ec5c29b..00000000 --- a/kernel/chips/pca9540.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * pca9540.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (c) 2004 Jean Delvare - * - * Based on pcf8574.c from the same project by Frodo Looijaard, - * Philip Edelbrock, Dan Eaton and Aurelien Jarno. - * - * The PCA9540 is a 2-channel I2C multiplexer made by Philips - * Semiconductors. It is controlled via the I2C bus itself. - * The SCL/SDA upstream pair fans out to two SCL/SDA downstream - * pairs, or channels. Only one SCL/SDA channel is selected at a - * time, determined by the contents of the programmable control - * register. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x70, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(pca9540); - -/* Each client has this additional data */ -struct pca9540_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - - u8 control; /* Register value */ -}; - -static int pca9540_attach_adapter(struct i2c_adapter *adapter); -static int pca9540_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int pca9540_detach_client(struct i2c_client *client); -static void pca9540_update_client(struct i2c_client *client); - -static void pca9540_channel(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* This is the driver that will be inserted */ -static struct i2c_driver pca9540_driver = { - .name = "PCA9540 chip driver", - .flags = I2C_DF_NOTIFY, - .attach_adapter = pca9540_attach_adapter, - .detach_client = pca9540_detach_client, -}; - - -/* -- SENSORS SYSCTL START -- */ - -#define PCA9540_SYSCTL_CHANNEL 1000 - -/* -- SENSORS SYSCTL END -- */ - -static ctl_table pca9540_dir_table_template[] = { - {PCA9540_SYSCTL_CHANNEL, "channel", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pca9540_channel}, - {0} -}; - -static int pca9540_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, pca9540_detect); -} - -/* This function is called by i2c_detect. */ -int pca9540_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct pca9540_data *data; - int err = 0; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. */ - if (!(data = kmalloc(sizeof(struct pca9540_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &pca9540_driver; - new_client->flags = 0; - - /* The detection is very weak. */ - if (kind < 0) { - u8 reg = i2c_smbus_read_byte(new_client); - if ((reg & 0xfa) != 0x00 - || reg != i2c_smbus_read_byte(new_client) - || reg != i2c_smbus_read_byte(new_client) - || reg != i2c_smbus_read_byte(new_client)) - goto ERROR1; - } - - kind = pca9540; - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, "PCA9540 chip"); - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR1; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, "pca9540", - pca9540_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR2; - } - data->sysctl_id = i; - - /* Initialize the PCA9540 chip: nothing needed */ - - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR2: - i2c_detach_client(new_client); - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int pca9540_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct pca9540_data *) (client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR "pca9540.o: Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -static void pca9540_update_client(struct i2c_client *client) -{ - struct pca9540_data *data = client->data; - - down(&data->update_lock); - -#ifdef DEBUG - printk(KERN_DEBUG "pca9540.o: Starting update.\n"); -#endif - data->control = i2c_smbus_read_byte(client) & 0x07; - - up(&data->update_lock); -} - - -void pca9540_channel(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct pca9540_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pca9540_update_client(client); - switch(data->control) { - case 4: results[0] = 1; break; - case 5: results[0] = 2; break; - default: results[0] = 0; - } - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - switch(results[0]) { - case 1: data->control = 4; break; - case 2: data->control = 5; break; - case 0: data->control = 0; break; - default: return; /* invalid value */ - } - i2c_smbus_write_byte(client, data->control); - } - } -} - - -static int __init pca9540_init(void) -{ - printk("pca9540.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&pca9540_driver); -} - -static void __exit pca9540_exit(void) -{ - i2c_del_driver(&pca9540_driver); -} - - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("PCA9540 driver"); - -module_init(pca9540_init); -module_exit(pca9540_exit); diff --git a/kernel/chips/pcf8574.c b/kernel/chips/pcf8574.c deleted file mode 100644 index 7026065b..00000000 --- a/kernel/chips/pcf8574.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - pcf8574.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2000 Frodo Looijaard , - Philip Edelbrock , - Dan Eaton - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* A few notes about the PCF8574: - -* The PCF8574 is an 8-bit I/O expander for the I2C bus produced by - Philips Semiconductors. It is designed to provide a byte I2C - interface to up to 8 separate devices. - -* The PCF8574 appears as a very simple SMBus device which can be - read from or written to with SMBUS byte read/write accesses. - -* Because of the general purpose nature of this device, it will most - likely be necessary to customize the /proc interface to suit the - specific application. - - --Dan - -*/ - - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x20, 0x27, 0x38, 0x3f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_2(pcf8574, pcf8574a); - -/* The PCF8574 registers */ - -/* (No registers. [Wow! This thing is SIMPLE!] ) */ - -/* Initial values */ -#define PCF8574_INIT 255 /* All outputs on (input mode) */ - -/* Each client has this additional data */ -struct pcf8574_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - - u8 read, write; /* Register values */ -}; - -static int pcf8574_attach_adapter(struct i2c_adapter *adapter); -static int pcf8574_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int pcf8574_detach_client(struct i2c_client *client); - -static void pcf8574_read(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pcf8574_write(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pcf8574_update_client(struct i2c_client *client); -static void pcf8574_init_client(struct i2c_client *client); - -/* This is the driver that will be inserted */ -static struct i2c_driver pcf8574_driver = { - .name = "PCF8574 sensor chip driver", - .id = I2C_DRIVERID_PCF8574, - .flags = I2C_DF_NOTIFY, - .attach_adapter = pcf8574_attach_adapter, - .detach_client = pcf8574_detach_client, -}; - - -/* -- SENSORS SYSCTL START -- */ -#define PCF8574_SYSCTL_READ 1000 -#define PCF8574_SYSCTL_WRITE 1001 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected PCF8574. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table pcf8574_dir_table_template[] = { - {PCF8574_SYSCTL_READ, "read", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8574_read}, - {PCF8574_SYSCTL_WRITE, "write", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8574_write}, - {0} -}; - -static int pcf8574_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, pcf8574_detect); -} - -/* This function is called by i2c_detect */ -static int pcf8574_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct pcf8574_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("pcf8574.o: pcf8574_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. */ - if (!(data = kmalloc(sizeof(struct pcf8574_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &pcf8574_driver; - new_client->flags = 0; - - /* Now, we would do the remaining detection. But the PCF8574 is plainly - impossible to detect! Stupid chip. */ - - /* Determine the chip type */ - if (kind <= 0) { - if (address >= 0x38 && address <= 0x3f) - kind = pcf8574a; - else - kind = pcf8574; - } - - if (kind == pcf8574a) { - type_name = "pcf8574a"; - client_name = "PCF8574A chip"; - } else { - type_name = "pcf8574"; - client_name = "PCF8574 chip"; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR1; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - pcf8574_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR2; - } - data->sysctl_id = i; - - /* Initialize the PCF8574 chip */ - pcf8574_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR2: - i2c_detach_client(new_client); - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int pcf8574_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct pcf8574_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("pcf8574.o: Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -/* Called when we have found a new PCF8574. */ -static void pcf8574_init_client(struct i2c_client *client) -{ - struct pcf8574_data *data = client->data; - data->write = PCF8574_INIT; - i2c_smbus_write_byte(client, data->write); -} - - -static void pcf8574_update_client(struct i2c_client *client) -{ - struct pcf8574_data *data = client->data; - - down(&data->update_lock); - -#ifdef DEBUG - printk("Starting pcf8574 update\n"); -#endif - - data->read = i2c_smbus_read_byte(client); - - up(&data->update_lock); -} - - -void pcf8574_read(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct pcf8574_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pcf8574_update_client(client); - results[0] = data->read; - *nrels_mag = 1; - } -} -void pcf8574_write(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct pcf8574_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->write; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->write = results[0]; - i2c_smbus_write_byte(client, data->write); - } - } -} - - -static int __init sm_pcf8574_init(void) -{ - printk("pcf8574.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&pcf8574_driver); -} - -static void __exit sm_pcf8574_exit(void) -{ - i2c_del_driver(&pcf8574_driver); -} - - -MODULE_AUTHOR("Frodo Looijaard , " - "Philip Edelbrock , " - "Dan Eaton and " - "Aurelien Jarno "); -MODULE_DESCRIPTION("PCF8574 driver"); - -module_init(sm_pcf8574_init); -module_exit(sm_pcf8574_exit); diff --git a/kernel/chips/pcf8591.c b/kernel/chips/pcf8591.c deleted file mode 100644 index 6f6de4c9..00000000 --- a/kernel/chips/pcf8591.c +++ /dev/null @@ -1,443 +0,0 @@ -/* - pcf8591.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2001 Aurelien Jarno - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x48, 0x4f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(pcf8591); - -/* The PCF8591 control byte */ -/* 7 6 5 4 3 2 1 0 */ -/* | 0 |AOEF| AIP | 0 |AINC| AICH | */ - -#define PCF8591_CONTROL_BYTE_AOEF 0x40 /* Analog Output Enable Flag */ - /* (analog output active if 1) */ - -#define PCF8591_CONTROL_BYTE_AIP 0x30 /* Analog Input Programming */ - /* 0x00 = four single ended inputs */ - /* 0x10 = three differential inputs */ - /* 0x20 = single ended and differential mixed */ - /* 0x30 = two differential inputs */ - -#define PCF8591_CONTROL_BYTE_AINC 0x04 /* Autoincrement Flag */ - /* (switch on if 1) */ - -#define PCF8591_CONTROL_BYTE_AICH 0x03 /* Analog Output Enable Flag */ - /* 0x00 = channel 0 */ - /* 0x01 = channel 1 */ - /* 0x02 = channel 2 */ - /* 0x03 = channel 3 */ - - -/* Initial values */ -#define PCF8591_INIT_CONTROL_BYTE (PCF8591_CONTROL_BYTE_AOEF | PCF8591_CONTROL_BYTE_AINC) - /* DAC out enabled, four single ended inputs, autoincrement */ - -#define PCF8591_INIT_AOUT 0 /* DAC out = 0 */ - - -/* Conversions. */ -#define REG_TO_SIGNED(reg) (reg & 0x80)?(reg - 256):(reg) - /* Convert signed 8 bit value to signed value */ - - -struct pcf8591_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 control_byte; - u8 ch[4]; - u8 aout; -}; - -static int pcf8591_attach_adapter(struct i2c_adapter *adapter); -static int pcf8591_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int pcf8591_detach_client(struct i2c_client *client); - -static void pcf8591_update_client(struct i2c_client *client); -static void pcf8591_init_client(struct i2c_client *client); - -static void pcf8591_ain_conf(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pcf8591_ain(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pcf8591_aout_enable(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void pcf8591_aout(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - - -/* This is the driver that will be inserted */ -static struct i2c_driver pcf8591_driver = { - .name = "PCF8591 sensor chip driver", - .id = I2C_DRIVERID_PCF8591, - .flags = I2C_DF_NOTIFY, - .attach_adapter = pcf8591_attach_adapter, - .detach_client = pcf8591_detach_client, -}; - -/* The /proc/sys entries */ - -/* -- SENSORS SYSCTL START -- */ -#define PCF8591_SYSCTL_AIN_CONF 1000 /* Analog input configuration */ -#define PCF8591_SYSCTL_CH0 1001 /* Input channel 1 */ -#define PCF8591_SYSCTL_CH1 1002 /* Input channel 2 */ -#define PCF8591_SYSCTL_CH2 1003 /* Input channel 3 */ -#define PCF8591_SYSCTL_CH3 1004 /* Input channel 4 */ -#define PCF8591_SYSCTL_AOUT_ENABLE 1005 /* Analog output enable flag */ -#define PCF8591_SYSCTL_AOUT 1006 /* Analog output */ -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected PCF8591. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table pcf8591_dir_table_template[] = { - {PCF8591_SYSCTL_AIN_CONF, "ain_conf", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8591_ain_conf}, - {PCF8591_SYSCTL_CH0, "ch0", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8591_ain}, - {PCF8591_SYSCTL_CH1, "ch1", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8591_ain}, - {PCF8591_SYSCTL_CH2, "ch2", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8591_ain}, - {PCF8591_SYSCTL_CH3, "ch3", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8591_ain}, - {PCF8591_SYSCTL_AOUT_ENABLE, "aout_enable", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8591_aout_enable}, - {PCF8591_SYSCTL_AOUT, "aout", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8591_aout}, - {0} -}; - - -/* This function is called when: - * pcf8591_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and pcf8591_driver is still present) */ -static int pcf8591_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, pcf8591_detect); -} - -/* This function is called by i2c_detect */ -static int pcf8591_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct pcf8591_data *data; - int err = 0; - - const char *type_name = ""; - const char *client_name = ""; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - (KERN_ERR "pcf8591.o: pcf8591_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE - | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. */ - if (!(data = kmalloc(sizeof(struct pcf8591_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &pcf8591_driver; - new_client->flags = 0; - - /* Now, we would do the remaining detection. But the PCF8591 is plainly - impossible to detect! Stupid chip. */ - - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = pcf8591; - - type_name = "pcf8591"; - client_name = "PCF8591 chip"; - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - pcf8591_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the PCF8591 chip */ - pcf8591_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - kfree(data); - ERROR0: - return err; -} - -static int pcf8591_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct pcf8591_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - (KERN_ERR "pcf8591.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -/* Called when we have found a new PCF8591. */ -static void pcf8591_init_client(struct i2c_client *client) -{ - struct pcf8591_data *data = client->data; - data->control_byte = PCF8591_INIT_CONTROL_BYTE; - data->aout = PCF8591_INIT_AOUT; - - i2c_smbus_write_byte_data(client, data->control_byte, data->aout); -} - -static void pcf8591_update_client(struct i2c_client *client) -{ - struct pcf8591_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk(KERN_DEBUG "Starting pcf8591 update\n"); -#endif - - i2c_smbus_write_byte(client, data->control_byte); - i2c_smbus_read_byte(client); /* The first byte transmitted contains the */ - /* conversion code of the previous read cycled */ - /* FLUSH IT ! */ - - - /* Number of byte to read to signed depend on the analog input mode */ - data->ch[0] = i2c_smbus_read_byte(client); - data->ch[1] = i2c_smbus_read_byte(client); - /* In all case, read at least two values */ - - if ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) != 0x30) - data->ch[2] = i2c_smbus_read_byte(client); - /* Read the third value if not in "two differential inputs" mode */ - - if ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 0x00) - data->ch[3] = i2c_smbus_read_byte(client); - /* Read the fourth value only in "four single ended inputs" mode */ - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. */ -void pcf8591_ain_conf(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pcf8591_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = (data->control_byte & PCF8591_CONTROL_BYTE_AIP) >> 4; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (results[0] >= 0 && results[0] <= 3) - { - data->control_byte &= ~PCF8591_CONTROL_BYTE_AIP; - data->control_byte |= (results[0] << 4); - i2c_smbus_write_byte(client, data->control_byte); - data->valid = 0; - } - } - } -} - -void pcf8591_ain(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pcf8591_data *data = client->data; - int nr = ctl_name - PCF8591_SYSCTL_CH0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - pcf8591_update_client(client); - - /* Number of data to show and conversion to signed depend on */ - /* the analog input mode */ - - switch(nr) { - case 0: - if (((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 0) - | ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 2)) - results[0] = data->ch[0]; /* single ended */ - else - results[0] = REG_TO_SIGNED(data->ch[0]);/* differential */ - break; - case 1: - if (((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 0) - | ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 2)) - results[0] = data->ch[1]; /* single ended */ - else - results[0] = REG_TO_SIGNED(data->ch[1]);/* differential */ - break; - case 2: - if ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 3) - results[0] = 0; /* channel not used */ - else if ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 0) - results[0] = data->ch[2]; /* single ended */ - else - results[0] = REG_TO_SIGNED(data->ch[2]);/* differential */ - break; - case 3: - if (((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 0) - | ((data->control_byte & PCF8591_CONTROL_BYTE_AIP) == 2)) - results[0] = data->ch[3]; /* single ended */ - else - results[0] = 0; /* channel not used */ - break; - } - *nrels_mag = 1; - } -} - -void pcf8591_aout_enable(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pcf8591_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = !(!(data->control_byte & PCF8591_CONTROL_BYTE_AOEF)); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (results[0]) - data->control_byte |= PCF8591_CONTROL_BYTE_AOEF; - else - data->control_byte &= ~PCF8591_CONTROL_BYTE_AOEF; - - i2c_smbus_write_byte(client, data->control_byte); - } - } -} - -void pcf8591_aout(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct pcf8591_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->aout; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (results[0] >= 0 && results[0] <= 255) /* ignore values outside DAC range */ - { - data->aout = results[0]; - i2c_smbus_write_byte_data(client, data->control_byte, data->aout); - } - } - } -} - -static int __init sm_pcf8591_init(void) -{ - printk(KERN_INFO "pcf8591.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&pcf8591_driver); -} - -static void __exit sm_pcf8591_exit(void) -{ - i2c_del_driver(&pcf8591_driver); -} - - - -MODULE_AUTHOR("Aurelien Jarno "); -MODULE_DESCRIPTION("PCF8591 driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_pcf8591_init); -module_exit(sm_pcf8591_exit); diff --git a/kernel/chips/saa1064.c b/kernel/chips/saa1064.c deleted file mode 100644 index 500c740c..00000000 --- a/kernel/chips/saa1064.c +++ /dev/null @@ -1,427 +0,0 @@ -/* - saa1064.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2003 Sascha Volkenandt - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* A few notes about the SAA1064: - -* The SAA1064 is a driver for 4-digit led displays produced by Philips - Semiconductors. It can be found in HiFi equipment with such displays. - I've found it inside a Kathrein analogue sat-receiver :-). - -* The SAA1064 is quite simple to handle, it receives an address byte, - telling which register is addressed, followed by up to five data - bytes (according to the data sheet), while with each byte the register - address is increased by one, wrapping from 7 to 0. - -* NOTE: This device doesn NOT have eight read-write registers, but eight - write-only registers, and one read-only status byte (with no register - address). - -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x38, 0x3b, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(saa1064); - -/* The SAA1064 registers - Registers: - 0 Control register - 1 Digit 1 - 2 Digit 2 - 3 Digit 3 - 4 Digit 4 -*/ - -#define SAA1064_REG_CONTROL 0x00 -#define SAA1064_REG_DIGIT0 0x01 -#define SAA1064_REG_DIGIT1 0x02 -#define SAA1064_REG_DIGIT2 0x03 -#define SAA1064_REG_DIGIT3 0x04 - -/* Control byte: - Bit 0 Dynamic mode - 1 Blank digits 1+3 (reversed) - 2 Blank digits 2+4 (reversed) - 3 Testmode (all digits on) - 4 Add 3mA output current to led's - 5 Add 6mA output current to led's - 6 Add 12mA output current to led's - 7 Unused, set to 0 -*/ - -#define SAA1064_CTRL_DYNAMIC 0x01 -#define SAA1064_CTRL_BLANK13 0x02 -#define SAA1064_CTRL_BLANK24 0x04 -#define SAA1064_CTRL_TEST 0x08 -#define SAA1064_CTRL_BRIGHT 0x70 - -/* Status byte: - The MSB set to 1 indicates powerloss since last read-out */ -#define SAA1064_STAT_PWRLOSS 0x80 - -/* Get a bit from the control-byte. Except for BRIGHT, these return - zero/non-zero in a boolean fashion. BRIGHT returns a 3-bit value - specifying the brightness */ -#define SAA1064_CTRL_GET_DYNAMIC(c) (((c) & SAA1064_CTRL_DYNAMIC)>0) -#define SAA1064_CTRL_GET_BLANK13(c) (((c) & SAA1064_CTRL_BLANK13)>0) -#define SAA1064_CTRL_GET_BLANK24(c) (((c) & SAA1064_CTRL_BLANK24)>0) -#define SAA1064_CTRL_GET_TEST(c) (((c) & SAA1064_CTRL_TEST)>0) -#define SAA1064_CTRL_GET_BRIGHT(c) (((c) & SAA1064_CTRL_BRIGHT)>>4) - -/* Get THE bit from the status byte. The LSB set to 1 indicates powerloss - since last read-out */ -#define SAA1064_STAT_GET_PWRLOSS(s) (((s) & SAA1064_STAT_PWRLOSS)>0) - -/* Set a bit in the control-byte to val and return the modified byte. - Except for BRIGHT, val is evaluated in a boolean fashion. */ -#define SAA1064_CTRL_SET_DYNAMIC(c,val) ((val)>0 \ - ? (c) | SAA1064_CTRL_DYNAMIC : (c) & ~SAA1064_CTRL_DYNAMIC) -#define SAA1064_CTRL_SET_BLANK13(c,val) ((val)>0 \ - ? (c) | SAA1064_CTRL_BLANK13 : (c) & ~SAA1064_CTRL_BLANK13) -#define SAA1064_CTRL_SET_BLANK24(c,val) ((val)>0 \ - ? (c) | SAA1064_CTRL_BLANK24 : (c) & ~SAA1064_CTRL_BLANK24) -#define SAA1064_CTRL_SET_TEST(c,val) ((val)>0 \ - ? (c) | SAA1064_CTRL_TEST : (c) & ~SAA1064_CTRL_TEST) -#define SAA1064_CTRL_SET_BRIGHT(c,val) (((c) & ~SAA1064_CTRL_BRIGHT) \ - | (((val) << 4) & SAA1064_CTRL_BRIGHT)) - -/* Initial values */ -#define SAA1064_INIT 0x7f /* All digits on (testmode), full brightness */ - -/* Each client has this additional data */ -struct saa1064_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 control; /* Control reg */ - u8 digits[4]; /* Digits regs */ - u8 status; /* Status byte (read) */ -}; - -static int saa1064_attach_adapter(struct i2c_adapter *adapter); -static int saa1064_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int saa1064_detach_client(struct i2c_client *client); - -static void saa1064_bright(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void saa1064_test(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void saa1064_disp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void saa1064_refresh(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void saa1064_update_client(struct i2c_client *client); -static void saa1064_init_client(struct i2c_client *client); - -/* This is the driver that will be inserted */ -static struct i2c_driver saa1064_driver = { - .name = "SAA1064 sensor chip driver", - .id = I2C_DRIVERID_SAA1064, - .flags = I2C_DF_NOTIFY, - .attach_adapter = saa1064_attach_adapter, - .detach_client = saa1064_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define SAA1064_SYSCTL_BRIGHT 1000 /* Brightness, 0-7 */ -#define SAA1064_SYSCTL_TEST 1001 /* Testmode (on = all digits lit) */ -#define SAA1064_SYSCTL_DISP 1005 /* four eight bit values */ -#define SAA1064_SYSCTL_REFRESH 1006 /* refresh digits in case of powerloss */ - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected SAA1064. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table saa1064_dir_table_template[] = { - {SAA1064_SYSCTL_BRIGHT, "bright", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &saa1064_bright}, - {SAA1064_SYSCTL_TEST, "test", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &saa1064_test}, - {SAA1064_SYSCTL_DISP, "disp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &saa1064_disp}, - {SAA1064_SYSCTL_REFRESH, "refresh", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &saa1064_refresh}, - {0} -}; - -static int saa1064_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, saa1064_detect); -} - -/* This function is called by i2c_detect */ -static int saa1064_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct saa1064_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("saa1064.o: saa1064_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE - | I2C_FUNC_SMBUS_WRITE_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access i2c_smbus_read_byte */ - if (!(data = kmalloc(sizeof(struct saa1064_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &saa1064_driver; - new_client->flags = 0; - - if (kind < 0) { - if ((i2c_smbus_read_byte(new_client) & ~SAA1064_STAT_PWRLOSS) != 0x00 - || i2c_smbus_read_byte(new_client) != 0x00 - || i2c_smbus_read_byte(new_client) != 0x00 - || i2c_smbus_read_byte(new_client) != 0x00) - goto ERROR1; - } - - /* If detection was requested, it has also passed til now. Only one chip, - so no further evaluation of kind. */ - kind = saa1064; - type_name = "saa1064"; - client_name = "SAA1064 chip"; - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - saa1064_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - -#ifdef DEBUG - printk("saa1064.o: Module initialization complete.\n"); -#endif - - /* Initialize the SAA1064 chip */ - saa1064_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - - -int saa1064_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct saa1064_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("saa1064.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -/* Called when we have found a new SAA1064. */ -void saa1064_init_client(struct i2c_client *client) -{ - struct saa1064_data *data = client->data; - data->control = SAA1064_INIT; - memset(data->digits, 0x00, 4); - - i2c_smbus_write_byte_data(client, SAA1064_REG_CONTROL, data->control); - i2c_smbus_write_i2c_block_data(client, SAA1064_REG_DIGIT0, 4, data->digits); -} - -/* Update status byte, and write registers in case a powerloss occurred */ -static void saa1064_update_client(struct i2c_client *client) -{ - struct saa1064_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 5*HZ) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("saa1064.o: starting saa1064 update\n"); -#endif - - data->status = i2c_smbus_read_byte(client); - if (SAA1064_STAT_GET_PWRLOSS(data->status)) { - i2c_smbus_write_byte_data(client, SAA1064_REG_CONTROL, data->control); - i2c_smbus_write_i2c_block_data(client, SAA1064_REG_DIGIT0, 4, data->digits); - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -static void saa1064_bright(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct saa1064_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = SAA1064_CTRL_GET_BRIGHT(data->control); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->control = SAA1064_CTRL_SET_BRIGHT(data->control, results[0]); - i2c_smbus_write_byte_data(client, SAA1064_REG_CONTROL, data->control); - } - } -} - - -static void saa1064_test(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct saa1064_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = SAA1064_CTRL_GET_TEST(data->control); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->control = SAA1064_CTRL_SET_TEST(data->control, results[0]); - i2c_smbus_write_byte_data(client, SAA1064_REG_CONTROL, data->control); - } - } -} - - -static void saa1064_disp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct saa1064_data *data = client->data; - int i; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - for (i = 0; i < 4; ++i) - results[i] = (long)data->digits[i]; - *nrels_mag = 4; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - for (i = 0; i < max(*nrels_mag, 4); ++i) - data->digits[i] = (u8)results[i]; - i2c_smbus_write_i2c_block_data(client, SAA1064_REG_DIGIT0, 4, data->digits); - } -} - - -static void saa1064_refresh(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - saa1064_update_client(client); - *nrels_mag = 0; - } -} - - -static int __init sensors_saa1064_init(void) -{ - printk("saa1064.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&saa1064_driver); -} - - -static void __exit sensors_saa1064_exit(void) -{ - i2c_del_driver(&saa1064_driver); -} - - - -MODULE_AUTHOR("Sascha Volkenandt "); -MODULE_DESCRIPTION("SAA1064 driver"); - -module_init(sensors_saa1064_init); -module_exit(sensors_saa1064_exit); - diff --git a/kernel/chips/sis5595.c b/kernel/chips/sis5595.c deleted file mode 100644 index 6c2e58ec..00000000 --- a/kernel/chips/sis5595.c +++ /dev/null @@ -1,721 +0,0 @@ -/* - sis5595.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Copyright (c) 1998 - 2001 Frodo Looijaard , - Kyösti Mälkki , and - Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - SiS southbridge has a LM78-like chip integrated on the same IC. - This driver is a customized copy of lm78.c - - Supports following revisions: - Version PCI ID PCI Revision - 1 1039/0008 AF or less - 2 1039/0008 B0 or greater - - Note: these chips contain a 0008 device which is incompatible with the - 5595. We recognize these by the presence of the listed - "blacklist" PCI ID and refuse to load. - - NOT SUPPORTED PCI ID BLACKLIST PCI ID - 540 0008 0540 - 550 0008 0550 - 5513 0008 5511 - 5581 0008 5597 - 5582 0008 5597 - 5597 0008 5597 - 5598 0008 5597/5598 - 630 0008 0630 - 645 0008 0645 - 730 0008 0730 - 735 0008 0735 -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* If force_addr is set to anything different from 0, we forcibly enable - the device at the given address. */ -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the sensors"); - -/* Addresses to scan. - Note that we can't determine the ISA address until we have initialized - our module */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(sis5595); - -static int blacklist[] = { - PCI_DEVICE_ID_SI_540, - PCI_DEVICE_ID_SI_550, - PCI_DEVICE_ID_SI_630, - PCI_DEVICE_ID_SI_645, - PCI_DEVICE_ID_SI_730, - PCI_DEVICE_ID_SI_735, - PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but - that ID shows up in other chips so we - use the 5511 ID for recognition */ - PCI_DEVICE_ID_SI_5597, - PCI_DEVICE_ID_SI_5598, - 0 }; - -/* Many SIS5595 constants specified below */ - -/* Length of ISA address segment */ -#define SIS5595_EXTENT 8 -/* PCI Config Registers */ -#define SIS5595_REVISION_REG 0x08 -#define SIS5595_BASE_REG 0x68 -#define SIS5595_PIN_REG 0x7A -#define SIS5595_ENABLE_REG 0x7B - -/* Where are the ISA address/data registers relative to the base address */ -#define SIS5595_ADDR_REG_OFFSET 5 -#define SIS5595_DATA_REG_OFFSET 6 - -/* The SIS5595 registers */ -#define SIS5595_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define SIS5595_REG_IN_MIN(nr) (0x2c + (nr) * 2) -#define SIS5595_REG_IN(nr) (0x20 + (nr)) - -#define SIS5595_REG_FAN_MIN(nr) (0x3a + (nr)) -#define SIS5595_REG_FAN(nr) (0x27 + (nr)) - -/* On the first version of the chip, the temp registers are separate. - On the second version, - TEMP pin is shared with IN4, configured in PCI register 0x7A. - The registers are the same as well. - OVER and HYST are really MAX and MIN. */ - -#define REV2MIN 0xb0 -#define SIS5595_REG_TEMP (( data->revision) >= REV2MIN) ? \ - SIS5595_REG_IN(4) : 0x27 -#define SIS5595_REG_TEMP_OVER (( data->revision) >= REV2MIN) ? \ - SIS5595_REG_IN_MAX(4) : 0x39 -#define SIS5595_REG_TEMP_HYST (( data->revision) >= REV2MIN) ? \ - SIS5595_REG_IN_MIN(4) : 0x3a - -#define SIS5595_REG_CONFIG 0x40 -#define SIS5595_REG_ALARM1 0x41 -#define SIS5595_REG_ALARM2 0x42 -#define SIS5595_REG_FANDIV 0x47 - -/* Conversions. Limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ - -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) -#define IN_FROM_REG(val) (((val) * 16 + 5) / 10) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm <= 0) - return 255; - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) - -/* Version 1 datasheet temp=.83*reg + 52.12 */ -#define TEMP_FROM_REG(val) (((((val)>=0x80?(val)-0x100:(val))*83)+5212)/10) -/* inverse 1.20*val - 62.77 */ -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?\ - ((((val)*12)-6327)/100):\ - ((((val)*12)-6227)/100)),0,255)) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) - -/* For the SIS5595, we need to keep some data in memory. It is - dynamically allocated, at the time when the new sis5595 client is - allocated. */ -struct sis5595_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - char maxins; /* == 3 if temp enabled, otherwise == 4 */ - u8 revision; /* Reg. value */ - - u8 in[5]; /* Register value */ - u8 in_max[5]; /* Register value */ - u8 in_min[5]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u8 temp; /* Register value */ - u8 temp_over; /* Register value */ - u8 temp_hyst; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u16 alarms; /* Register encoding, combined */ -}; - -static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */ - -static int sis5595_attach_adapter(struct i2c_adapter *adapter); -static int sis5595_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int sis5595_detach_client(struct i2c_client *client); - -static int sis5595_read_value(struct i2c_client *client, u8 register); -static int sis5595_write_value(struct i2c_client *client, u8 register, - u8 value); -static void sis5595_update_client(struct i2c_client *client); -static void sis5595_init_client(struct i2c_client *client); - - -static void sis5595_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void sis5595_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void sis5595_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void sis5595_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void sis5595_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* The driver. I choose to use type i2c_driver, as at is identical to both - smbus_driver and isa_driver, and clients could be of either kind */ -static struct i2c_driver sis5595_driver = { - .name = "SiS 5595", - .id = I2C_DRIVERID_SIS5595, - .flags = I2C_DF_NOTIFY, - .attach_adapter = sis5595_attach_adapter, - .detach_client = sis5595_detach_client, -}; - -/* The /proc/sys entries */ - -/* -- SENSORS SYSCTL START -- */ -#define SIS5595_SYSCTL_IN0 1000 /* Volts * 100 */ -#define SIS5595_SYSCTL_IN1 1001 -#define SIS5595_SYSCTL_IN2 1002 -#define SIS5595_SYSCTL_IN3 1003 -#define SIS5595_SYSCTL_IN4 1004 -#define SIS5595_SYSCTL_FAN1 1101 /* Rotations/min */ -#define SIS5595_SYSCTL_FAN2 1102 -#define SIS5595_SYSCTL_TEMP 1200 /* Degrees Celsius * 10 */ -#define SIS5595_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define SIS5595_SYSCTL_ALARMS 2001 /* bitvector */ - -#define SIS5595_ALARM_IN0 0x01 -#define SIS5595_ALARM_IN1 0x02 -#define SIS5595_ALARM_IN2 0x04 -#define SIS5595_ALARM_IN3 0x08 -#define SIS5595_ALARM_BTI 0x20 -#define SIS5595_ALARM_FAN1 0x40 -#define SIS5595_ALARM_FAN2 0x80 -#define SIS5595_ALARM_IN4 0x8000 -#define SIS5595_ALARM_TEMP 0x8000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected SIS5595. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table sis5595_dir_table_template[] = { - {SIS5595_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_in}, - {SIS5595_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_in}, - {SIS5595_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_in}, - {SIS5595_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_in}, - {SIS5595_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_in}, - {SIS5595_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_fan}, - {SIS5595_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_fan}, - {SIS5595_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_temp}, - {SIS5595_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_fan_div}, - {SIS5595_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &sis5595_alarms}, - {0} -}; - -/* This is called when the module is loaded */ -static int sis5595_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, sis5595_detect); -} - -/* Locate SiS bridge and correct base address for SIS5595 */ -static int __init sis5595_find_sis(int *address) -{ - u16 val; - int *i; - - if (!pci_present()) - return -ENODEV; - - if (!(s_bridge = - pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, - NULL))) - return -ENODEV; - - /* Look for imposters */ - for(i = blacklist; *i != 0; i++) { - if (pci_find_device(PCI_VENDOR_ID_SI, *i, NULL)) { - printk("sis5595.o: Error: Looked for SIS5595 but found unsupported device %.4X\n", *i); - return -ENODEV; - } - } - - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(s_bridge, SIS5595_BASE_REG, &val)) - return -ENODEV; - - *address = val & ~(SIS5595_EXTENT - 1); - if (*address == 0 && force_addr == 0) { - printk("sis5595.o: base address not set - upgrade BIOS or use force_addr=0xaddr\n"); - return -ENODEV; - } - if (force_addr) - *address = force_addr; /* so detect will get called */ - - return 0; -} - -int sis5595_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct sis5595_data *data; - int err = 0; - const char *type_name = "sis5595"; - const char *client_name = "SIS5595 chip"; - char val; - u16 a; - - /* Make sure we are probing the ISA bus!! */ - if (!i2c_is_isa_adapter(adapter)) { - printk - ("sis5595.o: sis5595_detect called for an I2C bus adapter?!?\n"); - return 0; - } - - if(force_addr) - address = force_addr & ~(SIS5595_EXTENT - 1); - if (check_region(address, SIS5595_EXTENT)) { - printk("sis5595.o: region 0x%x already in use!\n", address); - return -ENODEV; - } - if(force_addr) { - printk("sis5595.o: forcing ISA address 0x%04X\n", address); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(s_bridge, SIS5595_BASE_REG, address)) - return -ENODEV; - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a)) - return -ENODEV; - if ((a & ~(SIS5595_EXTENT - 1)) != address) { - /* doesn't work for some chips? */ - printk("sis5595.o: force address failed\n"); - return -ENODEV; - } - } - - if (PCIBIOS_SUCCESSFUL != - pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) - return -ENODEV; - if((val & 0x80) == 0) { - printk("sis5595.o: enabling sensors\n"); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG, - val | 0x80)) - return -ENODEV; - if (PCIBIOS_SUCCESSFUL != - pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) - return -ENODEV; - if((val & 0x80) == 0) { /* doesn't work for some chips! */ - printk("sis5595.o: sensors enable failed - not supported?\n"); - return -ENODEV; - } - } - - if (!(data = kmalloc(sizeof(struct sis5595_data), GFP_KERNEL))) { - return -ENOMEM; - } - - new_client = &data->client; - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &sis5595_driver; - new_client->flags = 0; - - /* Reserve the ISA region */ - request_region(address, SIS5595_EXTENT, type_name); - - /* Check revision and pin registers to determine whether 4 or 5 voltages */ - pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision)); - /* 4 voltages, 1 temp */ - data->maxins = 3; - if (data->revision >= REV2MIN) { - pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val); - if (!(val & 0x80)) - /* 5 voltages, no temp */ - data->maxins = 4; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry((struct i2c_client *) new_client, - type_name, - sis5595_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the SIS5595 chip */ - sis5595_init_client(new_client); - return 0; - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - release_region(address, SIS5595_EXTENT); - kfree(data); - return err; -} - -static int sis5595_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct sis5595_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("sis5595.o: Client deregistration failed, client not detached.\n"); - return err; - } - - release_region(client->addr, SIS5595_EXTENT); - kfree(client->data); - - return 0; -} - - -/* ISA access must be locked explicitly. - There are some ugly typecasts here, but the good news is - they should - nowhere else be necessary! */ -static int sis5595_read_value(struct i2c_client *client, u8 reg) -{ - int res; - - down(&(((struct sis5595_data *) (client->data))->lock)); - outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); - res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET); - up(&(((struct sis5595_data *) (client->data))->lock)); - return res; -} - -static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - down(&(((struct sis5595_data *) (client->data))->lock)); - outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET); - outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET); - up(&(((struct sis5595_data *) (client->data))->lock)); - return 0; -} - -/* Called when we have found a new SIS5595. */ -static void sis5595_init_client(struct i2c_client *client) -{ - u8 reg; - - /* Start monitoring */ - reg = i2c_smbus_read_byte_data(client, SIS5595_REG_CONFIG); - sis5595_write_value(client, SIS5595_REG_CONFIG, (reg|0x01)&0x7F); -} - -static void sis5595_update_client(struct i2c_client *client) -{ - struct sis5595_data *data = client->data; - int i; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - - for (i = 0; i <= data->maxins; i++) { - data->in[i] = - sis5595_read_value(client, SIS5595_REG_IN(i)); - data->in_min[i] = - sis5595_read_value(client, - SIS5595_REG_IN_MIN(i)); - data->in_max[i] = - sis5595_read_value(client, - SIS5595_REG_IN_MAX(i)); - } - for (i = 1; i <= 2; i++) { - data->fan[i - 1] = - sis5595_read_value(client, SIS5595_REG_FAN(i)); - data->fan_min[i - 1] = - sis5595_read_value(client, - SIS5595_REG_FAN_MIN(i)); - } - if(data->maxins == 3) { - data->temp = - sis5595_read_value(client, SIS5595_REG_TEMP); - data->temp_over = - sis5595_read_value(client, SIS5595_REG_TEMP_OVER); - data->temp_hyst = - sis5595_read_value(client, SIS5595_REG_TEMP_HYST); - } - i = sis5595_read_value(client, SIS5595_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = - sis5595_read_value(client, SIS5595_REG_ALARM1) | - (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ - -/* Return 0 for in4 and disallow writes if pin used for temp */ -void sis5595_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct sis5595_data *data = client->data; - int nr = ctl_name - SIS5595_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - if(nr <= 3 || data->maxins == 4) { - sis5595_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - } else { - results[0] = 0; - results[1] = 0; - results[2] = 0; - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if(nr <= 3 || data->maxins == 4) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0]); - sis5595_write_value(client, - SIS5595_REG_IN_MIN(nr), data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1]); - sis5595_write_value(client, - SIS5595_REG_IN_MAX(nr), data->in_max[nr]); - } - } - } -} - -void sis5595_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct sis5595_data *data = client->data; - int nr = ctl_name - SIS5595_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - sis5595_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - results[1] = FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = FAN_TO_REG(results[0], - DIV_FROM_REG - (data-> - fan_div[nr-1])); - sis5595_write_value(client, - SIS5595_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } - } -} - - -/* Return 0 for temp and disallow writes if pin used for in4 */ -void sis5595_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct sis5595_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - if(data->maxins == 3) { - sis5595_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - } else { - results[0] = 0; - results[1] = 0; - results[2] = 0; - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if(data->maxins == 3) { - if (*nrels_mag >= 1) { - data->temp_over = TEMP_TO_REG(results[0]); - sis5595_write_value(client, - SIS5595_REG_TEMP_OVER, data->temp_over); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - sis5595_write_value(client, - SIS5595_REG_TEMP_HYST, data->temp_hyst); - } - } - } -} - -void sis5595_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct sis5595_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - sis5595_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -void sis5595_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct sis5595_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - sis5595_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = sis5595_read_value(client, SIS5595_REG_FANDIV); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan_div[1] << 6); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div[0] << 4); - sis5595_write_value(client, SIS5595_REG_FANDIV, old); - } - } -} - -static int __init sm_sis5595_init(void) -{ - int addr; - - printk("sis5595.o version %s (%s)\n", LM_VERSION, LM_DATE); - - if (sis5595_find_sis(&addr)) { - printk("sis5595.o: SIS5595 not detected, module not inserted.\n"); - return -ENODEV; - } - normal_isa[0] = addr; - - return i2c_add_driver(&sis5595_driver); -} - -static void __exit sm_sis5595_exit(void) -{ - i2c_del_driver(&sis5595_driver); -} - - - -MODULE_AUTHOR("Kyösti Mälkki "); -MODULE_DESCRIPTION("SiS 5595 Sensor device"); - -module_init(sm_sis5595_init); -module_exit(sm_sis5595_exit); diff --git a/kernel/chips/smartbatt.c b/kernel/chips/smartbatt.c deleted file mode 100644 index 7dd145de..00000000 --- a/kernel/chips/smartbatt.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - smartbatt.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2002 M. D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - With GPL code from: - battery.c - Copyright (C) 2000 Linuxcare, Inc. - battery.h - Copyright (C) 2000 Hypercore Software Design, Ltd. -*/ - -#include -#include -#include -#include -#include -#include "version.h" - - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x0b, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(smartbatt); - -/* The SMARTBATT registers */ -#define SMARTBATT_REG_MODE 0x03 -#define SMARTBATT_REG_TEMP 0x08 -#define SMARTBATT_REG_V 0x09 -#define SMARTBATT_REG_I 0x0a -#define SMARTBATT_REG_AVGI 0x0b -#define SMARTBATT_REG_RELCHG 0x0d -#define SMARTBATT_REG_ABSCHG 0x0e -#define SMARTBATT_REG_REMCAP 0x0f -#define SMARTBATT_REG_CHGCAP 0x10 -#define SMARTBATT_REG_RUNTIME_E 0x11 -#define SMARTBATT_REG_AVGTIME_E 0x12 -#define SMARTBATT_REG_AVGTIME_F 0x13 -#define SMARTBATT_REG_CHGI 0x14 -#define SMARTBATT_REG_CHGV 0x15 -#define SMARTBATT_REG_STATUS 0x16 -#define SMARTBATT_REG_CYCLECT 0x17 -#define SMARTBATT_REG_DESCAP 0x18 -#define SMARTBATT_REG_DESV 0x19 -#define SMARTBATT_REG_DATE 0x1b -#define SMARTBATT_REG_SERIAL 0x1c -#define SMARTBATT_REG_MANUF 0x20 -#define SMARTBATT_REG_NAME 0x21 -#define SMARTBATT_REG_CHEM 0x22 - -#define BATTERY_STRING_MAX 64 -#define COMM_TIMEOUT 16 - - -/* Each client has this additional data */ -struct smartbatt_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ -#if 0 - char manufacturer[BATTERY_STRING_MAX]; - char device[BATTERY_STRING_MAX]; - char chemistry[BATTERY_STRING_MAX]; -#endif - int serial; - struct { - unsigned int day:5; /* Day (1-31) */ - unsigned int month:4; /* Month (1-12) */ - unsigned int year:7; /* Year (1980 + 0-127) */ - } manufacture_date; - u16 mode, temp, v, i, avgi; /* Register values */ - u16 relchg, abschg, remcap, chgcap; /* Register values */ - u16 rte, ate, atf, chgi, chgv; /* Register values */ - u16 status, cyclect, descap, desv; /* Register values */ -}; - -static int smartbatt_attach_adapter(struct i2c_adapter *adapter); -static int smartbatt_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void smartbatt_init_client(struct i2c_client *client); -static int smartbatt_detach_client(struct i2c_client *client); - -static int smartbatt_read(struct i2c_client *client, u8 reg); -#if 0 -static int smartbatt_write_value(struct i2c_client *client, u8 reg, u16 value); -#endif -static void smartbatt_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smartbatt_i(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smartbatt_v(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smartbatt_time(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smartbatt_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smartbatt_charge(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smartbatt_status(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smartbatt_error(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smartbatt_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver smartbatt_driver = { - .name = "Smart Battery chip driver", - .id = I2C_DRIVERID_SMARTBATT, - .flags = I2C_DF_NOTIFY, - .attach_adapter = smartbatt_attach_adapter, - .detach_client = smartbatt_detach_client, -}; - - -/* -- SENSORS SYSCTL START -- */ - -/* Status Register Bits */ -/* * * * * * Alarm Bits * * * * */ -#define SMARTBATT_OVER_CHARGED_ALARM 0x8000 -#define SMARTBATT_TERMINATE_CHARGE_ALARM 0x4000 -#define SMARTBATT_OVER_TEMP_ALARM 0x1000 -#define SMARTBATT_TERMINATE_DISCHARGE_ALARM 0x0800 -#define SMARTBATT_REMAINING_CAPACITY_ALARM 0x0200 -#define SMARTBATT_REMAINING_TIME_ALARM 0x0100 -/* * * * * * Status Bits * * * * */ -#define SMARTBATT_INITIALIZED 0x0080 -#define SMARTBATT_DISCHARGING 0x0040 -#define SMARTBATT_FULLY_CHARGED 0x0020 -#define SMARTBATT_FULLY_DISCHARGED 0x0010 -/* * * * * * Error Bits * * * * */ -#define SMARTBATT_OK 0x0000 -#define SMARTBATT_BUSY 0x0001 -#define SMARTBATT_RESERVED_COMMAND 0x0002 -#define SMARTBATT_UNSUPPORTED_COMMAND 0x0003 -#define SMARTBATT_ACCESS_DENIED 0x0004 -#define SMARTBATT_OVER_UNDERFLOW 0x0005 -#define SMARTBATT_BAD_SIZE 0x0006 -#define SMARTBATT_UNKNOWN_ERROR 0x0007 - -#define SMARTBATT_ALARM (SMARTBATT_OVER_CHARGED_ALARM \ - | SMARTBATT_TERMINATE_CHARGE_ALARM | SMARTBATT_OVER_TEMP_ALARM \ - | SMARTBATT_TERMINATE_DISCHARGE_ALARM \ - | SMARTBATT_REMAINING_CAPACITY_ALARM \ - | SMARTBATT_REMAINING_TIME_ALARM) - -#define SMARTBATT_STATUS (SMARTBATT_INITIALIZED | SMARTBATT_DISCHARGING \ - | SMARTBATT_FULLY_CHARGED | SMARTBATT_FULLY_DISCHARGED ) - -#define SMARTBATT_ERROR (SMARTBATT_BUSY | SMARTBATT_RESERVED_COMMAND \ - | SMARTBATT_UNSUPPORTED_COMMAND | SMARTBATT_ACCESS_DENIED \ - | SMARTBATT_OVER_UNDERFLOW | SMARTBATT_BAD_SIZE\ - | SMARTBATT_UNKNOWN_ERROR) - - -#define SMARTBATT_SYSCTL_I 1001 -#define SMARTBATT_SYSCTL_V 1002 -#define SMARTBATT_SYSCTL_TEMP 1003 -#define SMARTBATT_SYSCTL_TIME 1004 -#define SMARTBATT_SYSCTL_ALARMS 1005 -#define SMARTBATT_SYSCTL_STATUS 1006 -#define SMARTBATT_SYSCTL_ERROR 1007 -#define SMARTBATT_SYSCTL_CHARGE 1008 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected SMARTBATT. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table smartbatt_dir_table_template[] = { - {SMARTBATT_SYSCTL_I, "i", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smartbatt_i}, - {SMARTBATT_SYSCTL_V, "v", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smartbatt_v}, - {SMARTBATT_SYSCTL_TEMP, "temp", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smartbatt_temp}, - {SMARTBATT_SYSCTL_TIME, "time", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smartbatt_time}, - {SMARTBATT_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smartbatt_alarms}, - {SMARTBATT_SYSCTL_STATUS, "status", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smartbatt_status}, - {SMARTBATT_SYSCTL_ERROR, "error", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smartbatt_error}, - {SMARTBATT_SYSCTL_CHARGE, "charge", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smartbatt_charge}, - {0} -}; - -static int smartbatt_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, smartbatt_detect); -} - -/* This function is called by i2c_detect */ -int smartbatt_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct smartbatt_data *data; - int err = 0; - const char *type_name, *client_name; - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("smartbatt.o: smartbatt_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access smartbatt_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct smartbatt_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &smartbatt_driver; - new_client->flags = 0; - - /* Lousy detection. Check the temp, voltage, and current registers */ - if (kind < 0) { - for (i = 0x08; i <= 0x0a; i++) - if (i2c_smbus_read_word_data(new_client, i) == 0xffff) - goto ERROR1; - } - - kind = smartbatt; - type_name = "smartbatt"; - client_name = "Smart Battery"; - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - smartbatt_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - smartbatt_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int smartbatt_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct smartbatt_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("smartbatt.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - -static int smartbatt_read(struct i2c_client *client, u8 reg) -{ - int n = COMM_TIMEOUT; - int val; - do { - val = i2c_smbus_read_word_data(client, reg); - } while ((val == -1) && (n-- > 0)); - return val; -} - -#if 0 -static int smartbatt_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - /* Why swap bytes? */ - return i2c_smbus_write_word_data(client, reg, swab16(value)); -} -#endif - -#define COMM_TIMEOUT 16 -static void get_battery_info(struct i2c_client *client) -{ - struct smartbatt_data *data = client->data; - int val; - - down(&data->update_lock); - data->chgcap = smartbatt_read(client, SMARTBATT_REG_CHGCAP); - data->descap = smartbatt_read(client, SMARTBATT_REG_DESCAP); - data->desv = smartbatt_read(client, SMARTBATT_REG_DESV); - /* ManufactureDate */ - val = smartbatt_read(client, SMARTBATT_REG_DATE); - data->manufacture_date.day=val & 0x1F; - data->manufacture_date.month=(val >> 5) & 0x0F; - data->manufacture_date.year=(val >> 9) & 0x7F; - - /* SerialNumber */ - data->serial = smartbatt_read(client, SMARTBATT_REG_SERIAL); -#if 0 - /* ManufacturerName */ - n=COMM_TIMEOUT; - do { - val = i2c_smbus_read_block_data(client, 0x20, data->manufacturer); - } while ((val == -1) && (n-- > 0)); - data->manufacturer[val]=0; - - /* DeviceName */ - n=COMM_TIMEOUT; - do { - val = i2c_smbus_read_block_data(client, 0x21, data->device); - } while ((val == -1) && (n-- > 0)); - data->device[val]=0; - - /* DeviceChemistry */ - n=COMM_TIMEOUT; - do { - val = i2c_smbus_read_block_data(client, 0x22, data->chemistry); - } while ((val == -1) && (n-- > 0)); - data->chemistry[val]=0; -#endif - up(&data->update_lock); - -} - -static void smartbatt_init_client(struct i2c_client *client) -{ - get_battery_info( client ); -} - -static void smartbatt_update_client(struct i2c_client *client) -{ - struct smartbatt_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - data->mode = smartbatt_read(client, SMARTBATT_REG_MODE); - data->temp = smartbatt_read(client, SMARTBATT_REG_TEMP); - data->i = smartbatt_read(client, SMARTBATT_REG_I); - data->avgi = smartbatt_read(client, SMARTBATT_REG_AVGI); - data->v = smartbatt_read(client, SMARTBATT_REG_V); - data->chgi = smartbatt_read(client, SMARTBATT_REG_CHGI); - data->chgv = smartbatt_read(client, SMARTBATT_REG_CHGV); - data->ate = smartbatt_read(client, SMARTBATT_REG_AVGTIME_E); - data->atf = smartbatt_read(client, SMARTBATT_REG_AVGTIME_F); - data->rte = smartbatt_read(client, SMARTBATT_REG_RUNTIME_E); - data->status = smartbatt_read(client, SMARTBATT_REG_STATUS); - data->cyclect = smartbatt_read(client, SMARTBATT_REG_CYCLECT); - data->relchg = smartbatt_read(client, SMARTBATT_REG_RELCHG); - data->abschg = smartbatt_read(client, SMARTBATT_REG_ABSCHG); - data->remcap = smartbatt_read(client, SMARTBATT_REG_REMCAP); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void smartbatt_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smartbatt_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - smartbatt_update_client(client); - results[0] = data->temp - 2731; /* convert from Kelvin */ - *nrels_mag = 1; - } -} - -void smartbatt_i(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smartbatt_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - smartbatt_update_client(client); - results[0] = data->chgi; - results[1] = data->avgi; - results[2] = data->i; - *nrels_mag = 3; - } -} - -void smartbatt_v(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smartbatt_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - smartbatt_update_client(client); - results[0] = data->chgv; - results[1] = data->v; - *nrels_mag = 2; - } -} - -void smartbatt_time(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smartbatt_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - smartbatt_update_client(client); - results[0] = data->ate; - results[1] = data->atf; - results[2] = data->rte; - *nrels_mag = 3; - } -} - -void smartbatt_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smartbatt_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - smartbatt_update_client(client); - results[0] = data->status & SMARTBATT_ALARM; - *nrels_mag = 1; - } -} - -void smartbatt_status(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smartbatt_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - smartbatt_update_client(client); - results[0] = data->status & SMARTBATT_STATUS; - *nrels_mag = 1; - } -} - -void smartbatt_error(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smartbatt_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - smartbatt_update_client(client); - results[0] = data->status & SMARTBATT_ERROR; - *nrels_mag = 1; - } -} - -void smartbatt_charge(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smartbatt_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - smartbatt_update_client(client); - results[0] = data->relchg; - results[1] = data->abschg; - results[2] = data->chgi; - results[3] = data->chgv; - *nrels_mag = 4; - } -} - -static int __init sm_smartbatt_init(void) -{ - printk("smartbatt.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&smartbatt_driver); -} - -static void __exit sm_smartbatt_exit(void) -{ - i2c_del_driver(&smartbatt_driver); -} - - - -MODULE_AUTHOR("M. Studebaker "); -MODULE_DESCRIPTION("Smart Battery driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_smartbatt_init); -module_exit(sm_smartbatt_exit); diff --git a/kernel/chips/smbus-arp.c b/kernel/chips/smbus-arp.c deleted file mode 100644 index e4610078..00000000 --- a/kernel/chips/smbus-arp.c +++ /dev/null @@ -1,478 +0,0 @@ -/* - smbus-arp.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2002 Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include "version.h" - -#define DEBUG 1 - -/* So that the module will still compile without i2c-2.6.4; - if inserted, it will just put out a message and exit in that case */ -#ifdef I2C_CLIENT_PEC -#define I2C_PEC_SUPPORTED -#else -#define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ -#endif - -/* Addresses to scan */ -#define ARP_ADDRESS 0x61 -static unsigned short normal_i2c[] = { ARP_ADDRESS, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(arp); - -static int reset; -MODULE_PARM(reset, "i"); -MODULE_PARM_DESC(reset, - "Send an ARP Reset Device message to each bus"); - -/* ARP Commands */ -#define ARP_PREPARE 0x01 -#define ARP_RESET_DEV 0x02 -#define ARP_GET_UDID_GEN 0x03 -#define ARP_ASSIGN_ADDR 0x04 - -/* UDID Fields */ -#define ARP_CAPAB 0 -#define ARP_VER 1 -#define ARP_VEND 2 -#define ARP_DEV 4 -#define ARP_INT 6 -#define ARP_SUBVEND 8 -#define ARP_SUBDEV 10 -#define ARP_SPECID 12 - -#define UDID_LENGTH 0x11 - -static u8 reserved[] = -/* As defined by SMBus Spec. Appendix C */ - {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x28, - 0x37, ARP_ADDRESS, -/* As defined by SMBus Spec. Sect. 5.2 */ - 0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x78, 0x79, 0x7a, 0x7b, - 0x7c, 0x7d, 0x7e, 0x7f, -/* Common PC addresses (bad idea) */ - 0x2d, 0x48, 0x49, /* sensors */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* eeproms */ - 0x69, /* clock chips */ -/* Must end in 0 which is also reserved */ - 0x00}; - -#define SMBUS_ADDRESS_SIZE 0x80 -#define ARP_FREE 0 -#define ARP_RESERVED 1 -#define ARP_BUSY 2 - -#define ARP_MAX_DEVICES 8 -struct arp_device { - int status; - u8 udid[UDID_LENGTH]; - u8 dev_cap; - u8 dev_ver; - u16 dev_vid; - u16 dev_did; - u16 dev_int; - u16 dev_svid; - u16 dev_sdid; - u32 dev_vsid; - u8 saddr; -}; - -/* Each client has this additional data */ -struct arp_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 address_pool[SMBUS_ADDRESS_SIZE]; - struct arp_device dev[ARP_MAX_DEVICES]; -}; - - -static int smbusarp_attach_adapter(struct i2c_adapter *adapter); -static int smbusarp_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int smbusarp_detach_client(struct i2c_client *client); - -static int smbusarp_init_client(struct i2c_client *client); -static void smbusarp_contents(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver smbusarp_driver = { - .name = "SMBUS ARP", - .id = I2C_DRIVERID_ARP, - .flags = I2C_DF_NOTIFY, - .attach_adapter = smbusarp_attach_adapter, - .detach_client = smbusarp_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define ARP_SYSCTL1 1000 -#define ARP_SYSCTL2 1001 -#define ARP_SYSCTL3 1002 -#define ARP_SYSCTL4 1003 -#define ARP_SYSCTL5 1004 -#define ARP_SYSCTL6 1005 -#define ARP_SYSCTL7 1006 -#define ARP_SYSCTL8 1007 - -/* -- SENSORS SYSCTL END -- */ - -static ctl_table smbusarp_dir_table_template[] = { - {ARP_SYSCTL1, "0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smbusarp_contents}, - {ARP_SYSCTL2, "1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smbusarp_contents}, - {ARP_SYSCTL3, "2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smbusarp_contents}, - {ARP_SYSCTL4, "3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smbusarp_contents}, - {ARP_SYSCTL5, "4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smbusarp_contents}, - {ARP_SYSCTL6, "5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smbusarp_contents}, - {ARP_SYSCTL7, "6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smbusarp_contents}, - {ARP_SYSCTL8, "7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smbusarp_contents}, - {0} -}; - -static int smbusarp_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, smbusarp_detect); -} - -/* This function is called by i2c_detect */ -int smbusarp_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct arp_data *data; - int err = 0; - const char *type_name, *client_name; - - /* must support block data w/ HW PEC or SW PEC */ - if ((!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_HWPEC_CALC)) && - (!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_I2C))) - return(0); - - if (!(data = kmalloc(sizeof(struct arp_data), GFP_KERNEL))) { - return(-ENOMEM); - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &smbusarp_driver; -#ifdef I2C_PEC_SUPPORTED - new_client->flags = I2C_CLIENT_PEC; -#else - new_client->flags = 0; -#endif - - type_name = "arp"; - client_name = "SMBUS ARP client"; - - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - if ((err = i2c_attach_client(new_client))) - goto ERROR1; - - if ((i = i2c_register_entry(new_client, type_name, - smbusarp_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - smbusarp_init_client(new_client); - return 0; - - ERROR4: - i2c_detach_client(new_client); - ERROR1: - kfree(data); - return err; -} - -static int smbusarp_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct arp_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - (KERN_ERR "smbus-arp.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - - -static u8 choose_addr(u8 * pool) -{ - int i; - - for(i = 0; i < 0x7f; i++) { - if(pool[i] == ARP_FREE) - return ((u8) i); - } - return 0xff; -} - -static int smbusarp_init_client(struct i2c_client *client) -{ - int ret = -1; -#ifdef I2C_PEC_SUPPORTED - struct arp_data *data = client->data; - u8 blk[I2C_SMBUS_BLOCK_MAX]; - u8 *r; - u8 addr; - int i; - int found = 0; - int newdev = 0; - - for(i = 0; i < ARP_MAX_DEVICES; i++) - data->dev[i].status = ARP_FREE; - - for(i = 0; i < SMBUS_ADDRESS_SIZE; i++) - data->address_pool[i] = ARP_FREE; - - r = reserved; - do { - data->address_pool[*r] = ARP_RESERVED; - } while(*r++); - - for (i = 0; i < I2C_CLIENT_MAX ; i++) - if (client->adapter->clients[i]) - data->address_pool[client->adapter->clients[i]->addr] = - ARP_BUSY; - - if(reset) - i2c_smbus_write_byte(client, ARP_RESET_DEV); - ret = i2c_smbus_write_byte(client, ARP_PREPARE); - if(ret < 0) { -#ifdef DEBUG - printk(KERN_DEBUG "smbus-arp.o: No ARP response on adapter 0x%X\n", client->adapter->id); -#endif - return(-1); /* Packet wasn't acked */ - } - while(1) { - ret = i2c_smbus_read_block_data(client, ARP_GET_UDID_GEN, blk); - if(ret != UDID_LENGTH) { -#ifdef DEBUG - printk(KERN_DEBUG "smbus-arp.o: No/Bad UDID response %d on adapter 0x%X\n", ret, client->adapter->id); -#endif - if(found) - return(found); - else - return(-1); /* Bad response */ - } -#ifdef DEBUG - printk(KERN_DEBUG "smbus-arp.o: Good UDID response on adapter 0x%X\n", client->adapter->id); - printk(KERN_DEBUG " Cap. 0x%02x Rev. 0x%02x Vend. 0x%02x%02x Dev. 0x%02x%02x\n", blk[0], blk[1], blk[2], blk[3], blk[4], blk[5]); - printk(KERN_DEBUG " Int. 0x%02x%02x Subvend. 0x%02x%02x Subdev. 0x%02x%02x Spec. 0x%02x%02x%02x%02x\n", blk[6], blk[7], blk[8], blk[9], blk[10], blk[11], blk[12], blk[13], blk[14], blk[15]); -#endif -/* clean up this... */ - found++; - do{ - if(data->dev[newdev].status == ARP_FREE) - break; - } while(++newdev < ARP_MAX_DEVICES); - if(newdev == ARP_MAX_DEVICES) { - printk(KERN_WARNING "smbus-arp.o: No more slots available\n"); - return(-1); - } - - /* check device slave addr */ - addr = blk[16]; - if(addr != 0xFF) { - addr >>= 1; - if(blk[0] & 0xC0) { - if(data->address_pool[addr] == ARP_FREE) { -#ifdef DEBUG - printk(KERN_DEBUG " Requested free Non-fixed Address 0x%02x\n", addr); -#endif - } else { -#ifdef DEBUG - printk(KERN_DEBUG " Requested busy Non-fixed Address 0x%02x\n", addr); -#endif - if((addr = - choose_addr(data->address_pool)) == - 0xff) { - printk(KERN_WARNING "smbus-arp.o: Address pool exhausted\n"); - return(-1); - } - } - } else { -#ifdef DEBUG - printk(KERN_DEBUG " Fixed Address 0x%02x\n", addr); -#endif - } - } else { -#ifdef DEBUG - printk(KERN_DEBUG " No Address\n"); -#endif - if((addr = choose_addr(data->address_pool)) == 0xff) { - printk(KERN_WARNING "smbus-arp.o: Address pool exhausted\n"); - return(-1); - } - - } - /* store things both ways */ - for(i = 0; i < UDID_LENGTH; i++) - data->dev[newdev].udid[i] = blk[i]; - data->dev[newdev].saddr = addr; - data->dev[newdev].status = ARP_BUSY; - data->dev[newdev].dev_cap = blk[0]; - data->dev[newdev].dev_ver = blk[1]; - data->dev[newdev].dev_vid = (blk[2] << 8) | blk[3]; - data->dev[newdev].dev_did = (blk[4] << 8) | blk[5]; - data->dev[newdev].dev_int = (blk[6] << 8) | blk[7]; - data->dev[newdev].dev_svid = (blk[8] << 8) | blk[9]; - data->dev[newdev].dev_sdid = (blk[10] << 8) | blk[11]; - data->dev[newdev].dev_vsid = (blk[12] << 24) | (blk[13] << 16) | - (blk[14] << 8) | blk[15] ; - - blk[16] = addr << 1; - ret = i2c_smbus_write_block_data(client, ARP_ASSIGN_ADDR, - UDID_LENGTH, blk); - if(ret) { -#ifdef DEBUG - printk(KERN_DEBUG " Bad response, address 0x%02x not assigned\n", addr); -#endif - } else { - data->address_pool[addr] = ARP_BUSY; -#ifdef DEBUG - printk(KERN_DEBUG " Assigned address 0x%02x\n", addr); -#endif - } - /* retry? */ - - } /* while 1 */ -#else - printk(KERN_WARNING "smbus-arp.o: A client responded to the ARP address but " - "your kernel does not support SMBus ARP/PEC!\n"); - ret = -EPERM; -#endif - return(ret); -} - - -/* reassign address on writex */ -void smbusarp_contents(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - int nr = ctl_name - ARP_SYSCTL1; - struct arp_data *data = client->data; - int ret; - u8 save; - u8 a; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - if(data->dev[nr].status == ARP_BUSY) { - results[0] = data->dev[nr].saddr; - results[1] = data->dev[nr].dev_cap; - results[2] = data->dev[nr].dev_ver; - results[3] = data->dev[nr].dev_vid; - results[4] = data->dev[nr].dev_did; - results[5] = data->dev[nr].dev_int; - results[6] = data->dev[nr].dev_svid; - results[7] = data->dev[nr].dev_sdid; - results[8] = data->dev[nr].dev_vsid; - *nrels_mag = 9; - } else { - *nrels_mag = 0; - } - } else if (operation == SENSORS_PROC_REAL_WRITE) { - a = results[0]; - if(*nrels_mag >= 1 && - a < SMBUS_ADDRESS_SIZE && - data->dev[nr].status == ARP_BUSY && - data->address_pool[a] == ARP_FREE) { - save = data->dev[nr].udid[16]; - data->dev[nr].udid[16] = a << 1; - ret = i2c_smbus_write_block_data(client, ARP_ASSIGN_ADDR, - UDID_LENGTH, data->dev[nr].udid); - if(ret) { - data->dev[nr].udid[16] = save; -#ifdef DEBUG - printk(KERN_DEBUG "smbus-arp Bad response, address 0x%02x not assigned\n", a); -#endif - } else { - data->dev[nr].saddr = a; - data->address_pool[a] = ARP_BUSY; -#ifdef DEBUG - printk(KERN_DEBUG "smbus-arp Assigned address 0x%02x\n", a); -#endif - } - } else { - printk(KERN_WARNING "smbus-arp Bad address 0x%02x\n", a); - } - } -} - -static int __init sm_smbusarp_init(void) -{ - printk("smbus-arp.o version %s (%s)\n", LM_VERSION, LM_DATE); -/* magic force invocation */ - force_arp[0] = -1; - force_arp[1] = ARP_ADDRESS; - return i2c_add_driver(&smbusarp_driver); -} - -static void __exit sm_smbusarp_exit(void) -{ - i2c_del_driver(&smbusarp_driver); -} - - - -MODULE_AUTHOR("Mark D. Studebaker "); -MODULE_DESCRIPTION("SMBUS ARP Driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_smbusarp_init); -module_exit(sm_smbusarp_exit); diff --git a/kernel/chips/smsc47m1.c b/kernel/chips/smsc47m1.c deleted file mode 100644 index e464e9c9..00000000 --- a/kernel/chips/smsc47m1.c +++ /dev/null @@ -1,603 +0,0 @@ -/* - smsc47m1.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Copyright (c) 2002 Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" - -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the sensors"); - -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -SENSORS_INSMOD_2(smsc47m1, smsc47m2); -static u8 devid; - -/* modified from kernel/include/traps.c */ -#define REG 0x2e /* The register to read/write */ -#define DEV 0x07 /* Register: Logical device select */ -#define VAL 0x2f /* The value to read/write */ -#define PME 0x0a /* The device with the fan registers in it */ -#define DEVID 0x20 /* Register: Device ID */ - -static inline void -superio_outb(int reg, int val) -{ - outb(reg, REG); - outb(val, VAL); -} - -static inline int -superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -static inline void -superio_select(void) -{ - outb(DEV, REG); - outb(PME, VAL); -} - -static inline void -superio_enter(void) -{ - outb(0x55, REG); -} - -static inline void -superio_exit(void) -{ - outb(0xAA, REG); -} - -/* - * SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x - * (device id 0x5F) and LPC47B27x (device id 0x51) have fan control. - * The 47M15x and 47M192 chips "with hardware monitoring block" - * can do much more besides (device id 0x60). - * The LPC47M997 is undocumented, but seems to be compatible with - * the LPC47M192, and has the same device id. - * The LPC47M292 (device id 0x6B) is somewhat compatible, but it - * supports a 3rd fan, and the pin configuration registers are - * unfortunately different. - */ -#define SMSC_DEVID_MATCH(id) ((id) == 0x51 || (id) == 0x59 || \ - (id) == 0x5F || (id) == 0x60 || \ - (id) == 0x6B) - -#define SMSC_ACT_REG 0x30 -#define SMSC_BASE_REG 0x60 - -#define SMSC_EXTENT 0x80 - -#define SMSC47M1_REG_ALARM1 0x04 -#define SMSC47M1_REG_TPIN2 0x33 -#define SMSC47M1_REG_TPIN1 0x34 -#define SMSC47M1_REG_PPIN(nr) (0x37 - (nr)) -#define SMSC47M1_REG_FANDIV 0x58 - -static const u8 SMSC47M1_REG_PWM[3] = { 0x56, 0x57, 0x69 }; -static const u8 SMSC47M1_REG_FAN[3] = { 0x59, 0x5a, 0x6b }; -static const u8 SMSC47M1_REG_FAN_MIN[3] = { 0x5b, 0x5c, 0x6c }; - -#define SMSC47M2_REG_ALARM6 0x09 -#define SMSC47M2_REG_TPIN3 0x2d -#define SMSC47M2_REG_TPIN2 0x37 -#define SMSC47M2_REG_TPIN1 0x38 -#define SMSC47M2_REG_FANDIV3 0x6a - -static inline u8 MIN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 0; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT(192 - ((983040 + rpm * div / 2) / (rpm * div)), - 0, 191); -} - -#define MIN_FROM_REG(val,div) ((val)>=192?0: \ - 983040/((192-(val))*(div))) -#define FAN_FROM_REG(val,div,preload) ((val)==0?-1:(val)==255?0: \ - 983040/(((val)-preload)*(div))) -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) -/* reg is 6 middle bits; /proc is 8 bits */ -#define PWM_FROM_REG(val) (((val) << 1) & 0xfc) -#define PWM_TO_REG(val) (((SENSORS_LIMIT((val), 0, 255)) >> 1) & 0x7e) - -struct smsc47m1_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 alarms; /* Register encoding */ - u8 pwm[3]; /* Register value (bit 0 is disable) */ -}; - - -static int smsc47m1_attach_adapter(struct i2c_adapter *adapter); -static int smsc47m1_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int smsc47m1_detach_client(struct i2c_client *client); -static void smsc47m1_update_client(struct i2c_client *client); -static void smsc47m1_init_client(struct i2c_client *client); - - -static void smsc47m1_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smsc47m1_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smsc47m1_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void smsc47m1_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver smsc47m1_driver = { - .name = "SMSC 47M1xx fan monitor", - .id = I2C_DRIVERID_SMSC47M1, - .flags = I2C_DF_NOTIFY, - .attach_adapter = smsc47m1_attach_adapter, - .detach_client = smsc47m1_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define SMSC47M1_SYSCTL_FAN1 1101 /* Rotations/min */ -#define SMSC47M1_SYSCTL_FAN2 1102 -#define SMSC47M1_SYSCTL_FAN3 1103 -#define SMSC47M1_SYSCTL_PWM1 1401 -#define SMSC47M1_SYSCTL_PWM2 1402 -#define SMSC47M1_SYSCTL_PWM3 1403 -#define SMSC47M1_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define SMSC47M1_SYSCTL_ALARMS 2004 /* bitvector */ - -#define SMSC47M1_ALARM_FAN1 0x0001 -#define SMSC47M1_ALARM_FAN2 0x0002 -#define SMSC47M1_ALARM_FAN3 0x0004 - -/* -- SENSORS SYSCTL END -- */ - -static ctl_table smsc47m1_dir_table_template[] = { - {SMSC47M1_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_fan}, - {SMSC47M1_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_fan}, - {SMSC47M1_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_fan_div}, - {SMSC47M1_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_alarms}, - {SMSC47M1_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_pwm}, - {SMSC47M1_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_pwm}, - {0} -}; - -static ctl_table smsc47m2_dir_table_template[] = { - {SMSC47M1_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_fan}, - {SMSC47M1_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_fan}, - {SMSC47M1_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_fan}, - {SMSC47M1_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_fan_div}, - {SMSC47M1_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_alarms}, - {SMSC47M1_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_pwm}, - {SMSC47M1_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_pwm}, - {SMSC47M1_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &smsc47m1_pwm}, - {0} -}; - -static int smsc47m1_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, smsc47m1_detect); -} - -static int __init smsc47m1_find(int *address) -{ - u16 val; - - superio_enter(); - devid = superio_inb(DEVID); - if (!SMSC_DEVID_MATCH(devid)) { - superio_exit(); - return -ENODEV; - } - - superio_select(); - val = (superio_inb(SMSC_BASE_REG) << 8) | - superio_inb(SMSC_BASE_REG + 1); - *address = val & ~(SMSC_EXTENT - 1); - if (*address == 0 && force_addr == 0) { - printk("smsc47m1.o: base address not set - use force_addr=0xaddr\n"); - superio_exit(); - return -ENODEV; - } - if (force_addr) - *address = force_addr; /* so detect will get called */ - - superio_exit(); - return 0; -} - -int smsc47m1_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct smsc47m1_data *data; - int err = 0; - const char *type_name; - const char *client_name; - - if (!i2c_is_isa_adapter(adapter)) { - return 0; - } - - if(force_addr) - address = force_addr & ~(SMSC_EXTENT - 1); - if (check_region(address, SMSC_EXTENT)) { - printk("smsc47m1.o: region 0x%x already in use!\n", address); - return -ENODEV; - } - if(force_addr) { - printk("smsc47m1.o: forcing ISA address 0x%04X\n", address); - superio_enter(); - superio_select(); - superio_outb(SMSC_BASE_REG, address >> 8); - superio_outb(SMSC_BASE_REG+1, address & 0xff); - superio_exit(); - } - - if (!(data = kmalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) { - return -ENOMEM; - } - - switch (devid) { - case 0x51: - kind = smsc47m1; - type_name = "smsc47m1"; - client_name = "LPC47B27x chip"; - break; - case 0x5F: - kind = smsc47m1; - type_name = "smsc47m1"; - client_name = "LPC47M14x chip"; - break; - case 0x60: - kind = smsc47m1; - type_name = "smsc47m1"; - client_name = "LPC47M192 chip"; - break; - case 0x6B: - kind = smsc47m2; - type_name = "smsc47m2"; - client_name = "LPC47M292 chip"; - break; - default: - kind = smsc47m1; - type_name = "smsc47m1"; - client_name = "LPC47M1xx chip"; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &smsc47m1_driver; - new_client->flags = 0; - - request_region(address, SMSC_EXTENT, "smsc47m1-fans"); - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - if ((i = i2c_register_entry((struct i2c_client *) new_client, - type_name, - kind == smsc47m2 ? - smsc47m2_dir_table_template : - smsc47m1_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - smsc47m1_init_client(new_client); - return 0; - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - release_region(address, SMSC_EXTENT); - kfree(data); - return err; -} - -static int smsc47m1_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct smsc47m1_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("smsc47m1.o: Client deregistration failed, client not detached.\n"); - return err; - } - - release_region(client->addr, SMSC_EXTENT); - kfree(client->data); - - return 0; -} - -static inline int smsc47m1_read_value(struct i2c_client *client, u8 reg) -{ - return inb_p(client->addr + reg); -} - -static inline void smsc47m1_write_value(struct i2c_client *client, u8 reg, - u8 value) -{ - outb_p(value, client->addr + reg); -} - -static void smsc47m1_init_client(struct i2c_client *client) -{ - struct smsc47m1_data *data = client->data; - u8 reg; - - switch (data->type) { - case smsc47m2: - /* For the new LPC47M292 chip, I prefer to play it safe and - only report the pin configuration */ - reg = smsc47m1_read_value(client, SMSC47M2_REG_TPIN1); - if ((reg & 0x0d) != 0x09) - printk(KERN_NOTICE "smsc47m1: GP35 not configured for " - "fan input, ignore fan1 values\n"); - reg = smsc47m1_read_value(client, SMSC47M2_REG_TPIN2); - if ((reg & 0x0d) != 0x09) - printk(KERN_NOTICE "smsc47m1: GP34 not configured for " - "fan input, ignore fan2 values\n"); - reg = smsc47m1_read_value(client, SMSC47M2_REG_TPIN3); - if ((reg & 0x0d) != 0x0d) - printk(KERN_NOTICE "smsc47m1: GP33 not configured for " - "fan input, ignore fan3 values\n"); - break; - default: - /* configure pins for tach function */ - smsc47m1_write_value(client, SMSC47M1_REG_TPIN1, 0x05); - smsc47m1_write_value(client, SMSC47M1_REG_TPIN2, 0x05); - } -} - -static void smsc47m1_update_client(struct i2c_client *client) -{ - struct smsc47m1_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - int i, fan_nr; - fan_nr = data->type == smsc47m2 ? 3 : 2; - - for (i = 0; i < fan_nr; i++) { - data->fan[i] = - smsc47m1_read_value(client, SMSC47M1_REG_FAN[i]); - data->fan_min[i] = - smsc47m1_read_value(client, SMSC47M1_REG_FAN_MIN[i]); - data->pwm[i] = - smsc47m1_read_value(client, SMSC47M1_REG_PWM[i]); - } - - i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = - smsc47m1_read_value(client, SMSC47M1_REG_ALARM1) >> 6; - if(data->alarms) - smsc47m1_write_value(client, SMSC47M1_REG_ALARM1, 0xc0); - - if (fan_nr >= 3) { - data->fan_div[2] = (smsc47m1_read_value(client, - SMSC47M2_REG_FANDIV3) >> 4) & 0x03; - data->alarms |= (smsc47m1_read_value(client, - SMSC47M2_REG_ALARM6) & 0x40) >> 4; - if (data->alarms & 0x04) - smsc47m1_write_value(client, - SMSC47M2_REG_ALARM6, - 0x40); - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void smsc47m1_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smsc47m1_data *data = client->data; - int nr = ctl_name - SMSC47M1_SYSCTL_FAN1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - smsc47m1_update_client(client); - results[0] = MIN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - results[1] = FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr]), - data->fan_min[nr]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr] = MIN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr])); - smsc47m1_write_value(client, SMSC47M1_REG_FAN_MIN[nr], - data->fan_min[nr]); - } - } -} - - -void smsc47m1_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smsc47m1_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - smsc47m1_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -void smsc47m1_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct smsc47m1_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - smsc47m1_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV); - if (*nrels_mag >= 3 && data->type == smsc47m2) { - data->fan_div[2] = DIV_TO_REG(results[2]); - smsc47m1_write_value(client, SMSC47M2_REG_FANDIV3, - (smsc47m1_read_value(client, - SMSC47M2_REG_FANDIV3) & 0xcf) - | (data->fan_div[2] << 4)); - } - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan_div[1] << 6); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div[0] << 4); - smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, old); - } - } -} - -void smsc47m1_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct smsc47m1_data *data = client->data; - int nr = ctl_name - SMSC47M1_SYSCTL_PWM1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - smsc47m1_update_client(client); - results[0] = PWM_FROM_REG(data->pwm[nr]); - results[1] = !(data->pwm[nr] & 0x01); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->pwm[nr] = smsc47m1_read_value(client, - SMSC47M1_REG_PWM[nr]) & 0x81; - data->pwm[nr] |= PWM_TO_REG(results[0]); - if (*nrels_mag >= 2) { - if (results[1]) { - /* enable PWM */ - data->pwm[nr] &= 0xfe; - } else { - /* disable PWM */ - data->pwm[nr] |= 0x01; - } - } - smsc47m1_write_value(client, SMSC47M1_REG_PWM[nr], - data->pwm[nr]); - } - } -} - -static int __init sm_smsc47m1_init(void) -{ - int addr; - - printk("smsc47m1.o version %s (%s)\n", LM_VERSION, LM_DATE); - - if (smsc47m1_find(&addr)) { - printk("smsc47m1.o: SMSC 47M1xx not detected, module not inserted.\n"); - return -ENODEV; - } - normal_isa[0] = addr; - - return i2c_add_driver(&smsc47m1_driver); -} - -static void __exit sm_smsc47m1_exit(void) -{ - i2c_del_driver(&smsc47m1_driver); -} - - - -MODULE_AUTHOR("Mark D. Studebaker "); -MODULE_DESCRIPTION("SMSC 47M1xx Fan sensors"); -MODULE_LICENSE("GPL"); - -module_init(sm_smsc47m1_init); -module_exit(sm_smsc47m1_exit); diff --git a/kernel/chips/thmc50.c b/kernel/chips/thmc50.c deleted file mode 100644 index a0c50e7f..00000000 --- a/kernel/chips/thmc50.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - thmc50.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard and - Philip Edelbrock - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#define DEBUG 1 - -#include -#include -#include -#include -#include -#include "version.h" - -MODULE_LICENSE("GPL"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x2D, 0x2E, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(thmc50); - -/* Many THMC50 constants specified below */ - -/* The THMC50 registers */ -#define THMC50_REG_TEMP 0x27 -#define THMC50_REG_CONF 0x40 -#define THMC50_REG_TEMP_HYST 0x3A -#define THMC50_REG_TEMP_OS 0x39 - -#define THMC50_REG_TEMP_TRIP 0x13 -#define THMC50_REG_TEMP_REMOTE_TRIP 0x14 -#define THMC50_REG_TEMP_DEFAULT_TRIP 0x17 -#define THMC50_REG_TEMP_REMOTE_DEFAULT_TRIP 0x18 -#define THMC50_REG_ANALOG_OUT 0x19 -#define THMC50_REG_REMOTE_TEMP 0x26 -#define THMC50_REG_REMOTE_TEMP_HYST 0x38 -#define THMC50_REG_REMOTE_TEMP_OS 0x37 - -#define THMC50_REG_INTER 0x41 -#define THMC50_REG_INTER_MIRROR 0x4C -#define THMC50_REG_INTER_MASK 0x43 - -#define THMC50_REG_COMPANY_ID 0x3E -#define THMC50_REG_DIE_CODE 0x3F - - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define TEMP_FROM_REG(val) ((val>127)?val - 0x0100:val) -#define TEMP_TO_REG(val) ((val<0)?0x0100+val:val) - -/* Each client has this additional data */ -struct thmc50_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u16 temp, temp_os, temp_hyst, - remote_temp, remote_temp_os, remote_temp_hyst, - inter, inter_mask, die_code, analog_out; /* Register values */ -}; - -static int thmc50_attach_adapter(struct i2c_adapter *adapter); -static int thmc50_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void thmc50_init_client(struct i2c_client *client); -static int thmc50_detach_client(struct i2c_client *client); - -static int thmc50_read_value(struct i2c_client *client, u8 reg); -static int thmc50_write_value(struct i2c_client *client, u8 reg, - u16 value); -static void thmc50_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void thmc50_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, - long *results); -static void thmc50_inter(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void thmc50_inter_mask(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void thmc50_die_code(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void thmc50_analog_out(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void thmc50_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver thmc50_driver = { - .name = "THMC50 sensor chip driver", - .id = I2C_DRIVERID_THMC50, - .flags = I2C_DF_NOTIFY, - .attach_adapter = thmc50_attach_adapter, - .detach_client = thmc50_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define THMC50_SYSCTL_TEMP 1200 /* Degrees Celsius */ -#define THMC50_SYSCTL_REMOTE_TEMP 1201 /* Degrees Celsius */ -#define THMC50_SYSCTL_INTER 1202 -#define THMC50_SYSCTL_INTER_MASK 1203 -#define THMC50_SYSCTL_DIE_CODE 1204 -#define THMC50_SYSCTL_ANALOG_OUT 1205 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected THMC50. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table thmc50_dir_table_template[] = { - {THMC50_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &thmc50_temp}, - {THMC50_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &thmc50_remote_temp}, - {THMC50_SYSCTL_INTER, "inter", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &thmc50_inter}, - {THMC50_SYSCTL_INTER_MASK, "inter_mask", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &thmc50_inter_mask}, - {THMC50_SYSCTL_DIE_CODE, "die_code", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &thmc50_die_code}, - {THMC50_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &thmc50_analog_out}, - {0} -}; - - -static int thmc50_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, thmc50_detect); -} - -/* This function is called by i2c_detect */ -int thmc50_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int company, i; - struct i2c_client *new_client; - struct thmc50_data *data; - int err = 0; - const char *type_name, *client_name; - -#ifdef DEBUG - printk("thmc50.o: Probing for THMC50 at 0x%2X on bus %d\n", - address, adapter->id); -#endif - - /* Make sure we aren't probing the ISA bus!! This is just a safety check - at this moment; i2c_detect really won't call us. */ -#ifdef DEBUG - if (i2c_is_isa_adapter(adapter)) { - printk - ("thmc50.o: thmc50_detect called for an ISA bus adapter?!?\n"); - return 0; - } -#endif - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto ERROR0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access thmc50_{read,write}_value. */ - if (!(data = kmalloc(sizeof(struct thmc50_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &thmc50_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - company = - i2c_smbus_read_byte_data(new_client, THMC50_REG_COMPANY_ID); - - if (company != 0x49) { -#ifdef DEBUG - printk - ("thmc50.o: Detect of THMC50 failed (reg 3E: 0x%X)\n", - company); -#endif - goto ERROR1; - } - - /* Determine the chip type - only one kind supported! */ - kind = thmc50; - - if (kind == thmc50) { - type_name = "thmc50"; - client_name = "THMC50 chip"; - } else { -#ifdef DEBUG - printk("thmc50.o: Internal error: unknown kind (%d)?!?", - kind); -#endif - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - thmc50_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - thmc50_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int thmc50_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct thmc50_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("thmc50.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; -} - - -/* All registers are word-sized, except for the configuration register. - THMC50 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int thmc50_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -/* All registers are word-sized, except for the configuration register. - THMC50 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -static int thmc50_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static void thmc50_init_client(struct i2c_client *client) -{ - thmc50_write_value(client, THMC50_REG_CONF, 1); -} - -static void thmc50_update_client(struct i2c_client *client) -{ - struct thmc50_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting thmc50 update\n"); -#endif - - data->temp = thmc50_read_value(client, THMC50_REG_TEMP); - data->temp_os = - thmc50_read_value(client, THMC50_REG_TEMP_OS); - data->temp_hyst = - thmc50_read_value(client, THMC50_REG_TEMP_HYST); - data->remote_temp = - thmc50_read_value(client, THMC50_REG_REMOTE_TEMP); - data->remote_temp_os = - thmc50_read_value(client, THMC50_REG_REMOTE_TEMP_OS); - data->remote_temp_hyst = - thmc50_read_value(client, THMC50_REG_REMOTE_TEMP_HYST); - data->inter = thmc50_read_value(client, THMC50_REG_INTER); - data->inter_mask = - thmc50_read_value(client, THMC50_REG_INTER_MASK); - data->die_code = - thmc50_read_value(client, THMC50_REG_DIE_CODE); - data->analog_out = - thmc50_read_value(client, THMC50_REG_ANALOG_OUT); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void thmc50_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct thmc50_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - thmc50_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_os); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_os = TEMP_TO_REG(results[0]); - thmc50_write_value(client, THMC50_REG_TEMP_OS, - data->temp_os); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - thmc50_write_value(client, THMC50_REG_TEMP_HYST, - data->temp_hyst); - } - } -} - - -void thmc50_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct thmc50_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - thmc50_update_client(client); - results[0] = TEMP_FROM_REG(data->remote_temp_os); - results[1] = TEMP_FROM_REG(data->remote_temp_hyst); - results[2] = TEMP_FROM_REG(data->remote_temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->remote_temp_os = TEMP_TO_REG(results[0]); - thmc50_write_value(client, - THMC50_REG_REMOTE_TEMP_OS, - data->remote_temp_os); - } - if (*nrels_mag >= 2) { - data->remote_temp_hyst = TEMP_TO_REG(results[1]); - thmc50_write_value(client, - THMC50_REG_REMOTE_TEMP_HYST, - data->remote_temp_hyst); - } - } -} - - -void thmc50_inter(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct thmc50_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - thmc50_update_client(client); - results[0] = data->inter; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - printk("thmc50.o: No writes to Interrupt register!\n"); - } -} - - -void thmc50_inter_mask(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct thmc50_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - thmc50_update_client(client); - results[0] = data->inter_mask; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->inter_mask = results[0]; - thmc50_write_value(client, THMC50_REG_INTER_MASK, - data->inter_mask); - } - } -} - - -void thmc50_die_code(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct thmc50_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - thmc50_update_client(client); - results[0] = data->die_code; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - printk("thmc50.o: No writes to Die-Code register!\n"); - } -} - - -void thmc50_analog_out(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct thmc50_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - thmc50_update_client(client); - results[0] = data->analog_out; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->analog_out = results[0]; - thmc50_write_value(client, THMC50_REG_ANALOG_OUT, - data->analog_out); - } - } -} - - - - -static int __init sm_thmc50_init(void) -{ - printk("thmc50.o version %s (%s)\n", LM_VERSION, LM_DATE); - - return i2c_add_driver(&thmc50_driver); -} - -static void __exit sm_thmc50_exit(void) -{ - i2c_del_driver(&thmc50_driver); -} - - - -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("THMC50 driver"); - -module_init(sm_thmc50_init); -module_exit(sm_thmc50_exit); diff --git a/kernel/chips/via686a.c b/kernel/chips/via686a.c deleted file mode 100644 index 34321ee5..00000000 --- a/kernel/chips/via686a.c +++ /dev/null @@ -1,840 +0,0 @@ -/* - via686a.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Copyright (c) 1998 - 2002 Frodo Looijaard , - Kyösti Mälkki , - Mark Studebaker , - and Bob Dougherty - (Some conversion-factor data were contributed by Jonathan Teh Soon Yew - and Alex van Kaam .) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - Supports the Via VT82C686A, VT82C686B south bridges. - Reports all as a 686A. - See doc/chips/via686a for details. - Warning - only supports a single device. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_compat.h" - - -/* If force_addr is set to anything different from 0, we forcibly enable - the device at the given address. */ -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the sensors"); - -/* Addresses to scan. - Note that we can't determine the ISA address until we have initialized - our module */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(via686a); - -/* - The Via 686a southbridge has a LM78-like chip integrated on the same IC. - This driver is a customized copy of lm78.c -*/ - -/* Many VIA686A constants specified below */ - -/* Length of ISA address segment */ -#define VIA686A_EXTENT 0x80 -#define VIA686A_BASE_REG 0x70 -#define VIA686A_ENABLE_REG 0x74 - -/* The VIA686A registers */ -/* ins numbered 0-4 */ -#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2)) -#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2)) -#define VIA686A_REG_IN(nr) (0x22 + (nr)) - -/* fans numbered 1-2 */ -#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr)) -#define VIA686A_REG_FAN(nr) (0x28 + (nr)) - -// the following values are as speced by VIA: -static const u8 regtemp[] = { 0x20, 0x21, 0x1f }; -static const u8 regover[] = { 0x39, 0x3d, 0x1d }; -static const u8 reghyst[] = { 0x3a, 0x3e, 0x1e }; - -/* temps numbered 1-3 */ -#define VIA686A_REG_TEMP(nr) (regtemp[(nr) - 1]) -#define VIA686A_REG_TEMP_OVER(nr) (regover[(nr) - 1]) -#define VIA686A_REG_TEMP_HYST(nr) (reghyst[(nr) - 1]) -#define VIA686A_REG_TEMP_LOW1 0x4b // bits 7-6 -#define VIA686A_REG_TEMP_LOW23 0x49 // 2 = bits 5-4, 3 = bits 7-6 - -#define VIA686A_REG_ALARM1 0x41 -#define VIA686A_REG_ALARM2 0x42 -#define VIA686A_REG_FANDIV 0x47 -#define VIA686A_REG_CONFIG 0x40 -// The following register sets temp interrupt mode (bits 1-0 for temp1, -// 3-2 for temp2, 5-4 for temp3). Modes are: -// 00 interrupt stays as long as value is out-of-range -// 01 interrupt is cleared once register is read (default) -// 10 comparator mode- like 00, but ignores hysteresis -// 11 same as 00 -#define VIA686A_REG_TEMP_MODE 0x4b -// We'll just assume that you want to set all 3 simultaneously: -#define VIA686A_TEMP_MODE_MASK 0x3F -#define VIA686A_TEMP_MODE_CONTINUOUS (0x00) - -/* Conversions. Limit checking is only done on the TO_REG - variants. */ - -/********* VOLTAGE CONVERSIONS (Bob Dougherty) ********/ -// From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew): -// voltagefactor[0]=1.25/2628; (2628/1.25=2102.4) // Vccp -// voltagefactor[1]=1.25/2628; (2628/1.25=2102.4) // +2.5V -// voltagefactor[2]=1.67/2628; (2628/1.67=1573.7) // +3.3V -// voltagefactor[3]=2.6/2628; (2628/2.60=1010.8) // +5V -// voltagefactor[4]=6.3/2628; (2628/6.30=417.14) // +12V -// in[i]=(data[i+2]*25.0+133)*voltagefactor[i]; -// That is: -// volts = (25*regVal+133)*factor -// regVal = (volts/factor-133)/25 -// (These conversions were contributed by Jonathan Teh Soon Yew -// ) -static inline u8 IN_TO_REG(long val, int inNum) -{ - /* To avoid floating point, we multiply constants by 10 (100 for +12V). - Rounding is done (120500 is actually 133000 - 12500). - Remember that val is expressed in 0.01V/bit, which is why we divide - by an additional 1000 (10000 for +12V): 100 for val and 10 (100) - for the constants. */ - if (inNum <= 1) - return (u8) - SENSORS_LIMIT((val * 21024 - 120500) / 25000, 0, 255); - else if (inNum == 2) - return (u8) - SENSORS_LIMIT((val * 15737 - 120500) / 25000, 0, 255); - else if (inNum == 3) - return (u8) - SENSORS_LIMIT((val * 10108 - 120500) / 25000, 0, 255); - else - return (u8) - SENSORS_LIMIT((val * 41714 - 1205000) / 250000, 0, 255); -} - -static inline long IN_FROM_REG(u8 val, int inNum) -{ - /* To avoid floating point, we multiply constants by 10 (100 for +12V). - We also multiply them by 100 because we want 0.01V/bit for the - output value. Rounding is done. */ - if (inNum <= 1) - return (long) ((25000 * val + 133000 + 21024 / 2) / 21024); - else if (inNum == 2) - return (long) ((25000 * val + 133000 + 15737 / 2) / 15737); - else if (inNum == 3) - return (long) ((25000 * val + 133000 + 10108 / 2) / 10108); - else - return (long) ((250000 * val + 1330000 + 41714 / 2) / 41714); -} - -/********* FAN RPM CONVERSIONS ********/ -// Higher register values = slower fans (the fan's strobe gates a counter). -// But this chip saturates back at 0, not at 255 like all the other chips. -// So, 0 means 0 RPM -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 0; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255); -} - -#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1350000/((val)*(div))) - -/******** TEMP CONVERSIONS (Bob Dougherty) *********/ -// linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew) -// if(temp<169) -// return double(temp)*0.427-32.08; -// else if(temp>=169 && temp<=202) -// return double(temp)*0.582-58.16; -// else -// return double(temp)*0.924-127.33; -// -// A fifth-order polynomial fits the unofficial data (provided by Alex van -// Kaam ) a bit better. It also give more reasonable -// numbers on my machine (ie. they agree with what my BIOS tells me). -// Here's the fifth-order fit to the 8-bit data: -// temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - -// 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. -// -// (2000-10-25- RFD: thanks to Uwe Andersen for -// finding my typos in this formula!) -// -// Alas, none of the elegant function-fit solutions will work because we -// aren't allowed to use floating point in the kernel and doing it with -// integers doesn't provide enough precision. So we'll do boring old -// look-up table stuff. The unofficial data (see below) have effectively -// 7-bit resolution (they are rounded to the nearest degree). I'm assuming -// that the transfer function of the device is monotonic and smooth, so a -// smooth function fit to the data will allow us to get better precision. -// I used the 5th-order poly fit described above and solved for -// VIA register values 0-255. I *10 before rounding, so we get tenth-degree -// precision. (I could have done all 1024 values for our 10-bit readings, -// but the function is very linear in the useful range (0-80 deg C), so -// we'll just use linear interpolation for 10-bit readings.) So, tempLUT -// is the temp at via register values 0-255: -static const s16 tempLUT[] = - { -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, - -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, - -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, - -255, -246, -237, -229, -220, -212, -204, -196, -188, -180, - -173, -166, -159, -152, -145, -139, -132, -126, -120, -114, - -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49, - -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16, - 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84, - 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138, - 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189, - 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241, - 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294, - 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348, - 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404, - 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464, - 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532, - 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614, - 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718, - 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856, - 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044, - 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252, - 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462 -}; - -/* the original LUT values from Alex van Kaam - (for via register values 12-240): -{-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31, --30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15, --15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3, --3,-2,-2,-1,-1,0,0,1,1,1,3,3,3,4,4,4,5,5,5,6,6,7,7,8,8,9,9,9,10,10,11,11,12, -12,12,13,13,13,14,14,15,15,16,16,16,17,17,18,18,19,19,20,20,21,21,21,22,22, -22,23,23,24,24,25,25,26,26,26,27,27,27,28,28,29,29,30,30,30,31,31,32,32,33, -33,34,34,35,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45, -45,46,46,47,48,48,49,49,50,51,51,52,52,53,53,54,55,55,56,57,57,58,59,59,60, -61,62,62,63,64,65,66,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,83,84, -85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110}; -*/ - -// Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed -// an extra term for a good fit to these inverse data!) and then -// solving for each temp value from -50 to 110 (the useable range for -// this chip). Here's the fit: -// viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 -// - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01) -// Note that n=161: -static const u8 viaLUT[] = - { 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, - 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66, - 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100, - 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129, - 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156, - 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, - 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199, - 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213, - 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, - 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, - 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, - 239, 240 -}; - -/* Converting temps to (8-bit) hyst and over registers - No interpolation here. - The +50 is because the temps start at -50 */ -static inline u8 TEMP_TO_REG(long val) -{ - return viaLUT[val <= -500 ? 0 : val >= 1100 ? 160 : - (val < 0 ? val - 5 : val + 5) / 10 + 50]; -} - -/* for 8-bit temperature hyst and over registers */ -#define TEMP_FROM_REG(val) (tempLUT[(val)]) - -/* for 10-bit temperature readings */ -// You might _think_ this is too long to inline, but's it's really only -// called once... -static inline long TEMP_FROM_REG10(u16 val) -{ - // the temp values are already *10, so we don't need to do that. - long temp; - u16 eightBits = val >> 2; - u16 twoBits = val & 3; - - /* no interpolation for these */ - if (twoBits == 0 || eightBits == 255) - return (long) tempLUT[eightBits]; - - /* do some linear interpolation */ - temp = (4 - twoBits) * tempLUT[eightBits] - + twoBits * tempLUT[eightBits + 1]; - /* achieve rounding */ - return (temp < 0 ? temp - 2 : temp + 2) / 4; -} - -#define ALARMS_FROM_REG(val) (val) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) - -/* For the VIA686A, we need to keep some data in memory. - The structure is dynamically allocated, at the same time when a new - via686a client is allocated. */ -struct via686a_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[5]; /* Register value */ - u8 in_max[5]; /* Register value */ - u8 in_min[5]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u16 temp[3]; /* Register value 10 bit */ - u8 temp_over[3]; /* Register value */ - u8 temp_hyst[3]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u16 alarms; /* Register encoding, combined */ -}; - -static struct pci_dev *s_bridge; /* pointer to the (only) via686a */ - -static int via686a_attach_adapter(struct i2c_adapter *adapter); -static int via686a_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int via686a_detach_client(struct i2c_client *client); - -static int via686a_read_value(struct i2c_client *client, u8 register); -static void via686a_write_value(struct i2c_client *client, u8 register, - u8 value); -static void via686a_update_client(struct i2c_client *client); -static void via686a_init_client(struct i2c_client *client); - - -static void via686a_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void via686a_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void via686a_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void via686a_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void via686a_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* The driver. I choose to use type i2c_driver, as at is identical to both - smbus_driver and isa_driver, and clients could be of either kind */ -static struct i2c_driver via686a_driver = { - .name = "VIA 686A", - .id = I2C_DRIVERID_VIA686A, - .flags = I2C_DF_NOTIFY, - .attach_adapter = via686a_attach_adapter, - .detach_client = via686a_detach_client, -}; - - - -/* The /proc/sys entries */ - -/* -- SENSORS SYSCTL START -- */ -#define VIA686A_SYSCTL_IN0 1000 -#define VIA686A_SYSCTL_IN1 1001 -#define VIA686A_SYSCTL_IN2 1002 -#define VIA686A_SYSCTL_IN3 1003 -#define VIA686A_SYSCTL_IN4 1004 -#define VIA686A_SYSCTL_FAN1 1101 -#define VIA686A_SYSCTL_FAN2 1102 -#define VIA686A_SYSCTL_TEMP 1200 -#define VIA686A_SYSCTL_TEMP2 1201 -#define VIA686A_SYSCTL_TEMP3 1202 -#define VIA686A_SYSCTL_FAN_DIV 2000 -#define VIA686A_SYSCTL_ALARMS 2001 - -#define VIA686A_ALARM_IN0 0x01 -#define VIA686A_ALARM_IN1 0x02 -#define VIA686A_ALARM_IN2 0x04 -#define VIA686A_ALARM_IN3 0x08 -#define VIA686A_ALARM_TEMP 0x10 -#define VIA686A_ALARM_FAN1 0x40 -#define VIA686A_ALARM_FAN2 0x80 -#define VIA686A_ALARM_IN4 0x100 -#define VIA686A_ALARM_TEMP2 0x800 -#define VIA686A_ALARM_CHAS 0x1000 -#define VIA686A_ALARM_TEMP3 0x8000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected VIA686A. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table via686a_dir_table_template[] = { - {VIA686A_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &via686a_in}, - {VIA686A_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &via686a_in}, - {VIA686A_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &via686a_in}, - {VIA686A_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &via686a_in}, - {VIA686A_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &via686a_in}, - {VIA686A_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &via686a_fan}, - {VIA686A_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &via686a_fan}, - {VIA686A_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &via686a_temp}, - {VIA686A_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &via686a_temp}, - {VIA686A_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &via686a_temp}, - {VIA686A_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &via686a_fan_div}, - {VIA686A_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &via686a_alarms}, - {0} -}; - -static inline int via686a_read_value(struct i2c_client *client, u8 reg) -{ - return (inb_p(client->addr + reg)); -} - -static inline void via686a_write_value(struct i2c_client *client, u8 reg, - u8 value) -{ - outb_p(value, client->addr + reg); -} - -/* This is called when the module is loaded */ -static int via686a_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, via686a_detect); -} - -int via686a_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct via686a_data *data; - int err = 0; - const char *type_name = "via686a"; - u16 val; - - /* Make sure we are probing the ISA bus!! */ - if (!i2c_is_isa_adapter(adapter)) { - printk - ("via686a.o: via686a_detect called for an I2C bus adapter?!?\n"); - return 0; - } - - /* 8231 requires multiple of 256, we enforce that on 686 as well */ - if(force_addr) - address = force_addr & 0xFF00; - if (check_region(address, VIA686A_EXTENT)) { - printk("via686a.o: region 0x%x already in use!\n", - address); - return -ENODEV; - } - - if(force_addr) { - printk("via686a.o: forcing ISA address 0x%04X\n", address); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(s_bridge, VIA686A_BASE_REG, address)) - return -ENODEV; - } - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val)) - return -ENODEV; - if (!(val & 0x0001)) { - printk("via686a.o: enabling sensors\n"); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(s_bridge, VIA686A_ENABLE_REG, - val | 0x0001)) - return -ENODEV; - } - - if (!(data = kmalloc(sizeof(struct via686a_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &via686a_driver; - new_client->flags = 0; - - /* Reserve the ISA region */ - request_region(address, VIA686A_EXTENT, "via686a-sensors"); - - /* Fill in the remaining client fields and put into the global list */ - strcpy(new_client->name, "Via 686A Integrated Sensors"); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry((struct i2c_client *) new_client, - type_name, - via686a_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* Initialize the VIA686A chip */ - via686a_init_client(new_client); - return 0; - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - release_region(address, VIA686A_EXTENT); - kfree(data); - ERROR0: - return err; -} - -static int via686a_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct via686a_data *) - (client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("via686a.o: Client deregistration failed, client not detached.\n"); - return err; - } - - release_region(client->addr, VIA686A_EXTENT); - kfree(client->data); - - return 0; -} - -/* Called when we have found a new VIA686A. */ -static void via686a_init_client(struct i2c_client *client) -{ - u8 reg; - - /* Start monitoring */ - reg = via686a_read_value(client, VIA686A_REG_CONFIG); - via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F); - - /* Configure temp interrupt mode for continuous-interrupt operation */ - via686a_write_value(client, VIA686A_REG_TEMP_MODE, - via686a_read_value(client, VIA686A_REG_TEMP_MODE) & - !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS)); -} - -static void via686a_update_client(struct i2c_client *client) -{ - struct via686a_data *data = client->data; - int i; - - down(&data->update_lock); - - if (time_after(jiffies - data->last_updated, HZ + HZ / 2) || - time_before(jiffies, data->last_updated) || !data->valid) { - - for (i = 0; i <= 4; i++) { - data->in[i] = - via686a_read_value(client, VIA686A_REG_IN(i)); - data->in_min[i] = via686a_read_value(client, - VIA686A_REG_IN_MIN - (i)); - data->in_max[i] = - via686a_read_value(client, VIA686A_REG_IN_MAX(i)); - } - for (i = 1; i <= 2; i++) { - data->fan[i - 1] = - via686a_read_value(client, VIA686A_REG_FAN(i)); - data->fan_min[i - 1] = via686a_read_value(client, - VIA686A_REG_FAN_MIN(i)); - } - for (i = 1; i <= 3; i++) { - data->temp[i - 1] = via686a_read_value(client, - VIA686A_REG_TEMP(i)) << 2; - data->temp_over[i - 1] = - via686a_read_value(client, - VIA686A_REG_TEMP_OVER(i)); - data->temp_hyst[i - 1] = - via686a_read_value(client, - VIA686A_REG_TEMP_HYST(i)); - } - /* add in lower 2 bits - temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 - temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23 - temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23 - */ - data->temp[0] |= (via686a_read_value(client, - VIA686A_REG_TEMP_LOW1) - & 0xc0) >> 6; - data->temp[1] |= - (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) & - 0x30) >> 4; - data->temp[2] |= - (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) & - 0xc0) >> 6; - - i = via686a_read_value(client, VIA686A_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = - via686a_read_value(client, - VIA686A_REG_ALARM1) | - (via686a_read_value(client, VIA686A_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -static void via686a_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct via686a_data *data = client->data; - int nr = ctl_name - VIA686A_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - via686a_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr], nr); - results[1] = IN_FROM_REG(data->in_max[nr], nr); - results[2] = IN_FROM_REG(data->in[nr], nr); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0], nr); - via686a_write_value(client, VIA686A_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1], nr); - via686a_write_value(client, VIA686A_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void via686a_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct via686a_data *data = client->data; - int nr = ctl_name - VIA686A_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - via686a_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data->fan_div - [nr - 1])); - results[1] = FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = FAN_TO_REG(results[0], - DIV_FROM_REG(data-> - fan_div[nr -1])); - via686a_write_value(client, - VIA686A_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } - } -} - -void via686a_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct via686a_data *data = client->data; - int nr = ctl_name - VIA686A_SYSCTL_TEMP; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - via686a_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over[nr]); - results[1] = TEMP_FROM_REG(data->temp_hyst[nr]); - results[2] = TEMP_FROM_REG10(data->temp[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over[nr] = TEMP_TO_REG(results[0]); - via686a_write_value(client, - VIA686A_REG_TEMP_OVER(nr + 1), - data->temp_over[nr]); - } - if (*nrels_mag >= 2) { - data->temp_hyst[nr] = TEMP_TO_REG(results[1]); - via686a_write_value(client, - VIA686A_REG_TEMP_HYST(nr + 1), - data->temp_hyst[nr]); - } - } -} - -void via686a_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct via686a_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - via686a_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void via686a_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct via686a_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - via686a_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = via686a_read_value(client, VIA686A_REG_FANDIV); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan_div[1] << 6); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div[0] << 4); - via686a_write_value(client, VIA686A_REG_FANDIV, - old); - } - } -} - - -static struct pci_device_id via686a_pci_ids[] __devinitdata = { - {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, } -}; - -static int __devinit via686a_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - u16 val; - int addr = 0; - - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(dev, VIA686A_BASE_REG, &val)) - return -ENODEV; - - addr = val & ~(VIA686A_EXTENT - 1); - if (addr == 0 && force_addr == 0) { - printk("via686a.o: base address not set - upgrade BIOS or use force_addr=0xaddr\n"); - return -ENODEV; - } - if (force_addr) - addr = force_addr; /* so detect will get called */ - - normal_isa[0] = addr; - s_bridge = dev; - return i2c_add_driver(&via686a_driver); -} - -static void __devexit via686a_pci_remove(struct pci_dev *dev) -{ - i2c_del_driver(&via686a_driver); -} - -static struct pci_driver via686a_pci_driver = { - .name = "via686a", - .id_table = via686a_pci_ids, - .probe = via686a_pci_probe, - .remove = __devexit_p(via686a_pci_remove), -}; - -static int __init sm_via686a_init(void) -{ - printk("via686a.o version %s (%s)\n", LM_VERSION, LM_DATE); - return pci_module_init(&via686a_pci_driver); -} - -static void __exit sm_via686a_exit(void) -{ - pci_unregister_driver(&via686a_pci_driver); -} - -MODULE_AUTHOR("Kyösti Mälkki , " - "Mark Studebaker " - "and Bob Dougherty "); -MODULE_DESCRIPTION("VIA 686A Sensor device"); -MODULE_LICENSE("GPL"); - -module_init(sm_via686a_init); -module_exit(sm_via686a_exit); diff --git a/kernel/chips/vt1211.c b/kernel/chips/vt1211.c deleted file mode 100644 index 37346f1c..00000000 --- a/kernel/chips/vt1211.c +++ /dev/null @@ -1,820 +0,0 @@ -/* - vt1211.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Copyright (c) 2002 Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* Supports VIA VT1211 Super I/O sensors via ISA (LPC) accesses only. */ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" - -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the sensors"); - -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -SENSORS_INSMOD_1(vt1211); - -/* modified from kernel/include/traps.c */ -#define REG 0x2e /* The register to read/write */ -#define DEV 0x07 /* Register: Logical device select */ -#define VAL 0x2f /* The value to read/write */ -#define PME 0x0b /* The device with the hardware monitor */ -#define DEVID 0x20 /* Register: Device ID */ - -static inline void -superio_outb(int reg, int val) -{ - outb(reg, REG); - outb(val, VAL); -} - -static inline int -superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -static inline void -superio_select(void) -{ - outb(DEV, REG); - outb(PME, VAL); -} - -static inline void -superio_enter(void) -{ - outb(0x87, REG); - outb(0x87, REG); -} - -static inline void -superio_exit(void) -{ - outb(0xAA, REG); -} - -#define VT1211_DEVID 0x3c -#define VT1211_ACT_REG 0x30 -#define VT1211_BASE_REG 0x60 - -#define VT1211_EXTENT 0x80 - -/* pwm numbered 1-2 */ -#define VT1211_REG_PWM(nr) (0x5f + (nr)) -#define VT1211_REG_PWM_CTL 0x51 - -/* The VT1211 registers */ -/* We define the sensors as follows. Somewhat convoluted to minimize - changes from via686a. - Sensor Voltage Mode Temp Mode - -------- ------------ --------- - Reading 1 temp1 Intel thermal diode - Reading 3 temp2 VT1211 internal thermal diode - UCH1/Reading2 in0 temp3 - UCH2 in1 temp4 - UCH3 in2 temp5 - UCH4 in3 temp6 - UCH5 in4 temp7 - 3.3V in5 -*/ - -/* ins numbered 0-5 */ -#define VT1211_REG_IN_MAX(nr) ((nr)==0 ? 0x3d : 0x29 + ((nr) * 2)) -#define VT1211_REG_IN_MIN(nr) ((nr)==0 ? 0x3e : 0x2a + ((nr) * 2)) -#define VT1211_REG_IN(nr) (0x21 + (nr)) - -/* fans numbered 1-2 */ -#define VT1211_REG_FAN_MIN(nr) (0x3a + (nr)) -#define VT1211_REG_FAN(nr) (0x28 + (nr)) - -static const u8 regtemp[] = { 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25 }; -static const u8 regover[] = { 0x39, 0x1d, 0x3d, 0x2b, 0x2d, 0x2f, 0x31 }; -static const u8 reghyst[] = { 0x3a, 0x1e, 0x3e, 0x2c, 0x2e, 0x30, 0x32 }; - -/* temps numbered 1-7 */ -#define VT1211_REG_TEMP(nr) (regtemp[(nr) - 1]) -#define VT1211_REG_TEMP_OVER(nr) (regover[(nr) - 1]) -#define VT1211_REG_TEMP_HYST(nr) (reghyst[(nr) - 1]) -#define VT1211_REG_TEMP_LOW1 0x4b /* bits 7-6 */ -#define VT1211_REG_TEMP_LOW3 0x49 /* bits 5-4 */ -#define VT1211_REG_TEMP_LOW47 0x4d - -#define VT1211_REG_CONFIG 0x40 -#define VT1211_REG_ALARM1 0x41 -#define VT1211_REG_ALARM2 0x42 -#define VT1211_REG_VID 0x45 -#define VT1211_REG_FANDIV 0x47 -#define VT1211_REG_UCH_CONFIG 0x4a -#define VT1211_REG_TEMP1_CONFIG 0x4b -#define VT1211_REG_TEMP2_CONFIG 0x4c - -/* temps 1-7; voltages 0-5 */ -#define ISTEMP(i, ch_config) ((i) <= 2 ? 1 : \ - ((ch_config) >> ((i)-1)) & 1) -#define ISVOLT(i, ch_config) ((i) > 4 ? 1 : !(((ch_config) >> ((i)+2)) & 0x01)) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) -#define PWM_FROM_REG(val) (val) -#define PWM_TO_REG(val) SENSORS_LIMIT((val), 0, 255) - -/* temp1 (i = 1) is an Intel thermal diode which is scaled in user space. - temp2 (i = 2) is the internal temp diode so it's scaled in the driver - according to some measurements taken on an EPIA M10000. - temp3-7 are thermistor based so the driver returns the voltage measured at - the pin (range 0V - 2.2V). */ -#define TEMP_FROM_REG(i, reg) ((i) == 1 ? (reg) * 10 : \ - (i) == 2 ? (reg) < 51 ? 0 : \ - ((reg) - 51) * 10 : \ - ((253 - (reg)) * 2200 + 105) / 210) -/* for 10-bit temp values */ -#define TEMP_FROM_REG10(i, reg) ((i) == 1 ? (reg) * 10 / 4 : \ - (i) == 2 ? (reg) < 204 ? 0 : \ - ((reg) - 204) * 10 / 4 : \ - ((1012 - (reg)) * 550 + 105) / 210) -#define TEMP_TO_REG(i, val) SENSORS_LIMIT( \ - ((i) == 1 ? ((val) + 5) / 10 : \ - (i) == 2 ? ((val) + 5) / 10 + 51 : \ - 253 - ((val) * 210 + 1100) / 2200), 0, 255) - -/* in5 (i = 5) is special. It's the internal 3.3V so it's scaled in the - driver according to the VT1211 BIOS porting guide */ -#define IN_FROM_REG(i, reg) ((reg) < 3 ? 0 : (i) == 5 ? \ - (((reg) - 3) * 15882 + 4790) / 9580 : \ - (((reg) - 3) * 10000 + 4790) / 9580) -#define IN_TO_REG(i, val) (SENSORS_LIMIT((i) == 5 ? \ - ((val) * 9580 + 7941) / 15882 + 3 : \ - ((val) * 9580 + 5000) / 10000 + 3, 0, 255)) - -/********* FAN RPM CONVERSIONS ********/ -/* But this chip saturates back at 0, not at 255 like all the other chips. - So, 0 means 0 RPM */ -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 0; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1310720 + rpm * div / 2) / (rpm * div), 1, 255); -} - -#define MIN_TO_REG(a,b) FAN_TO_REG(a,b) -#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1310720/((val)*(div))) - -struct vt1211_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[6]; /* Register value */ - u8 in_max[6]; /* Register value */ - u8 in_min[6]; /* Register value */ - u16 temp[7]; /* Register value 10 bit */ - u8 temp_over[7]; /* Register value */ - u8 temp_hyst[7]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u16 alarms; /* Register encoding */ - u8 pwm[2]; /* Register value */ - u8 pwm_ctl; /* Register value */ - u8 vid; /* Register encoding */ - u8 vrm; - u8 uch_config; -}; - -static int vt1211_attach_adapter(struct i2c_adapter *adapter); -static int vt1211_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int vt1211_detach_client(struct i2c_client *client); - -static inline int vt_rdval(struct i2c_client *client, u8 register); -static inline void vt1211_write_value(struct i2c_client *client, u8 register, - u8 value); -static void vt1211_update_client(struct i2c_client *client); -static void vt1211_init_client(struct i2c_client *client); - - -static void vt1211_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt1211_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt1211_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt1211_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt1211_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt1211_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt1211_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt1211_uch(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt1211_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver vt1211_driver = { - .name = "VT1211 sensors driver", - .id = I2C_DRIVERID_VT1211, - .flags = I2C_DF_NOTIFY, - .attach_adapter = vt1211_attach_adapter, - .detach_client = vt1211_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define VT1211_SYSCTL_IN0 1000 -#define VT1211_SYSCTL_IN1 1001 -#define VT1211_SYSCTL_IN2 1002 -#define VT1211_SYSCTL_IN3 1003 -#define VT1211_SYSCTL_IN4 1004 -#define VT1211_SYSCTL_IN5 1005 -#define VT1211_SYSCTL_FAN1 1101 -#define VT1211_SYSCTL_FAN2 1102 -#define VT1211_SYSCTL_TEMP1 1200 -#define VT1211_SYSCTL_TEMP2 1201 -#define VT1211_SYSCTL_TEMP3 1202 -#define VT1211_SYSCTL_TEMP4 1203 -#define VT1211_SYSCTL_TEMP5 1204 -#define VT1211_SYSCTL_TEMP6 1205 -#define VT1211_SYSCTL_TEMP7 1206 -#define VT1211_SYSCTL_VID 1300 -#define VT1211_SYSCTL_PWM1 1401 -#define VT1211_SYSCTL_PWM2 1402 -#define VT1211_SYSCTL_VRM 1600 -#define VT1211_SYSCTL_UCH 1700 -#define VT1211_SYSCTL_FAN_DIV 2000 -#define VT1211_SYSCTL_ALARMS 2001 - -#define VT1211_ALARM_IN1 0x01 -#define VT1211_ALARM_IN2 0x02 -#define VT1211_ALARM_IN5 0x04 -#define VT1211_ALARM_IN3 0x08 -#define VT1211_ALARM_TEMP1 0x10 -#define VT1211_ALARM_FAN1 0x40 -#define VT1211_ALARM_FAN2 0x80 -#define VT1211_ALARM_IN4 0x100 -#define VT1211_ALARM_TEMP3 0x800 -#define VT1211_ALARM_CHAS 0x1000 -#define VT1211_ALARM_TEMP2 0x8000 -/* duplicates */ -#define VT1211_ALARM_IN0 VT1211_ALARM_TEMP3 -#define VT1211_ALARM_TEMP4 VT1211_ALARM_IN1 -#define VT1211_ALARM_TEMP5 VT1211_ALARM_IN2 -#define VT1211_ALARM_TEMP6 VT1211_ALARM_IN3 -#define VT1211_ALARM_TEMP7 VT1211_ALARM_IN4 - -/* -- SENSORS SYSCTL END -- */ - -static ctl_table vt1211_dir_table_template[] = { - {VT1211_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_in}, - {VT1211_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_in}, - {VT1211_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_in}, - {VT1211_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_in}, - {VT1211_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_in}, - {VT1211_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_in}, - {VT1211_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp}, - {VT1211_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp}, - {VT1211_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp}, - {VT1211_SYSCTL_TEMP4, "temp4", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp}, - {VT1211_SYSCTL_TEMP5, "temp5", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp}, - {VT1211_SYSCTL_TEMP6, "temp6", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp}, - {VT1211_SYSCTL_TEMP7, "temp7", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt1211_temp}, - {VT1211_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_fan}, - {VT1211_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_fan}, - {VT1211_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_fan_div}, - {VT1211_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_alarms}, - {VT1211_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_pwm}, - {VT1211_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_pwm}, - {VT1211_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_vid}, - {VT1211_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_vrm}, - {VT1211_SYSCTL_UCH, "uch_config", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt1211_uch}, - {0} -}; - -static int vt1211_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, vt1211_detect); -} - -static int __init vt1211_find(int *address) -{ - u16 val; - - superio_enter(); - val= superio_inb(DEVID); - if(VT1211_DEVID != val) { - superio_exit(); - return -ENODEV; - } - - superio_select(); - val = (superio_inb(VT1211_BASE_REG) << 8) | - superio_inb(VT1211_BASE_REG + 1); - *address = val & ~(VT1211_EXTENT - 1); - if (*address == 0 && force_addr == 0) { - printk("vt1211.o: base address not set - use force_addr=0xaddr\n"); - superio_exit(); - return -ENODEV; - } - if (force_addr) - *address = force_addr; /* so detect will get called */ - - superio_exit(); - return 0; -} - -int vt1211_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct vt1211_data *data; - int err = 0; - u8 val; - const char *type_name = "vt1211"; - const char *client_name = "VT1211 chip"; - - if (!i2c_is_isa_adapter(adapter)) { - return 0; - } - - if(force_addr) - address = force_addr & ~(VT1211_EXTENT - 1); - if (check_region(address, VT1211_EXTENT)) { - printk("vt1211.o: region 0x%x already in use!\n", address); - return -ENODEV; - } - if(force_addr) { - printk("vt1211.o: forcing ISA address 0x%04X\n", address); - superio_enter(); - superio_select(); - superio_outb(VT1211_BASE_REG, address >> 8); - superio_outb(VT1211_BASE_REG+1, address & 0xff); - superio_exit(); - } - - superio_enter(); - superio_select(); - if((val = 0x01 & superio_inb(VT1211_ACT_REG)) == 0) - superio_outb(VT1211_ACT_REG, 1); - superio_exit(); - - if (!(data = kmalloc(sizeof(struct vt1211_data), GFP_KERNEL))) { - return -ENOMEM; - } - - new_client = &data->client; - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &vt1211_driver; - new_client->flags = 0; - - request_region(address, VT1211_EXTENT, "vt1211-sensors"); - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - if ((i = i2c_register_entry((struct i2c_client *) new_client, - type_name, - vt1211_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - vt1211_init_client(new_client); - return 0; - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - release_region(address, VT1211_EXTENT); - kfree(data); - return err; -} - -static int vt1211_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct vt1211_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("vt1211.o: Client deregistration failed, client not detached.\n"); - return err; - } - - release_region(client->addr, VT1211_EXTENT); - kfree(client->data); - - return 0; -} - -static inline int vt_rdval(struct i2c_client *client, u8 reg) -{ - return (inb_p(client->addr + reg)); -} - -static inline void vt1211_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - outb_p(value, client->addr + reg); -} - -static void vt1211_init_client(struct i2c_client *client) -{ - struct vt1211_data *data = client->data; - - data->vrm = 91; - /* set "default" interrupt mode for alarms, which isn't the default */ - vt1211_write_value(client, VT1211_REG_TEMP1_CONFIG, 0); - vt1211_write_value(client, VT1211_REG_TEMP2_CONFIG, 0); -} - -static void vt1211_update_client(struct i2c_client *client) -{ - struct vt1211_data *data = client->data; - int i, j; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - data->uch_config = vt_rdval(client, VT1211_REG_UCH_CONFIG); - for (i = 0; i <= 5; i++) { - if(ISVOLT(i, data->uch_config)) { - data->in[i] = vt_rdval(client, VT1211_REG_IN(i)); - data->in_min[i] = vt_rdval(client, - VT1211_REG_IN_MIN(i)); - data->in_max[i] = vt_rdval(client, - VT1211_REG_IN_MAX(i)); - } else { - data->in[i] = 0; - data->in_min[i] = 0; - data->in_max[i] = 0; - } - } - for (i = 1; i <= 2; i++) { - data->fan[i - 1] = vt_rdval(client, VT1211_REG_FAN(i)); - data->fan_min[i - 1] = vt_rdval(client, - VT1211_REG_FAN_MIN(i)); - } - for (i = 1; i <= 7; i++) { - if(ISTEMP(i, data->uch_config)) { - data->temp[i - 1] = vt_rdval(client, - VT1211_REG_TEMP(i)) << 2; - switch(i) { - case 1: - j = (vt_rdval(client, - VT1211_REG_TEMP_LOW1) >> - 6) & 3; - break; - case 2: - j = 0; - break; - case 3: - j = (vt_rdval(client, - VT1211_REG_TEMP_LOW3) >> - 4) & 3; - break; - default: - j = (vt_rdval(client, - VT1211_REG_TEMP_LOW47) >> - ((i-4)*2)) & 0x03; - } - data->temp[i - 1] |= j; - data->temp_over[i - 1] = vt_rdval(client, - VT1211_REG_TEMP_OVER(i)); - data->temp_hyst[i - 1] = vt_rdval(client, - VT1211_REG_TEMP_HYST(i)); - } else { - data->temp[i - 1] = 0; - data->temp_over[i - 1] = 0; - data->temp_hyst[i - 1] = 0; - } - } - - for (i = 1; i <= 2; i++) { - data->fan[i - 1] = vt_rdval(client, VT1211_REG_FAN(i)); - data->fan_min[i - 1] = vt_rdval(client, - VT1211_REG_FAN_MIN(i)); - data->pwm[i - 1] = vt_rdval(client, VT1211_REG_PWM(i)); - } - - data->pwm_ctl = vt_rdval(client, VT1211_REG_PWM_CTL); - i = vt_rdval(client, VT1211_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = vt_rdval(client, VT1211_REG_ALARM1) | - (vt_rdval(client, VT1211_REG_ALARM2) << 8); - data->vid= vt_rdval(client, VT1211_REG_VID) & 0x1f; - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void vt1211_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt1211_data *data = client->data; - int nr = ctl_name - VT1211_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - vt1211_update_client(client); - results[0] = IN_FROM_REG(nr, data->in_min[nr]); - results[1] = IN_FROM_REG(nr, data->in_max[nr]); - results[2] = IN_FROM_REG(nr, data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(nr, results[0]); - vt1211_write_value(client, VT1211_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(nr, results[1]); - vt1211_write_value(client, VT1211_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void vt1211_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt1211_data *data = client->data; - int nr = ctl_name - VT1211_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - vt1211_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data->fan_div - [nr - 1])); - results[1] = FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = MIN_TO_REG(results[0], - DIV_FROM_REG - (data-> - fan_div[nr-1])); - vt1211_write_value(client, VT1211_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } - } -} - - -void vt1211_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt1211_data *data = client->data; - int nr = ctl_name - VT1211_SYSCTL_TEMP1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = nr < 2 ? 1 : 3; - else if (operation == SENSORS_PROC_REAL_READ) { - vt1211_update_client(client); - results[0] = TEMP_FROM_REG(nr + 1, data->temp_over[nr]); - results[1] = TEMP_FROM_REG(nr + 1, data->temp_hyst[nr]); - results[2] = TEMP_FROM_REG10(nr + 1, data->temp[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over[nr] = TEMP_TO_REG(nr + 1, results[0]); - vt1211_write_value(client, - VT1211_REG_TEMP_OVER(nr + 1), - data->temp_over[nr]); - } - if (*nrels_mag >= 2) { - data->temp_hyst[nr] = TEMP_TO_REG(nr + 1, results[1]); - vt1211_write_value(client, - VT1211_REG_TEMP_HYST(nr + 1), - data->temp_hyst[nr]); - } - } -} - -void vt1211_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt1211_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - vt1211_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -void vt1211_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct vt1211_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - vt1211_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = vt_rdval(client, VT1211_REG_FANDIV); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan_div[1] << 6); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div[0] << 4); - vt1211_write_value(client, VT1211_REG_FANDIV, old); - } - } -} - -void vt1211_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt1211_data *data = client->data; - int nr = 1 + ctl_name - VT1211_SYSCTL_PWM1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - vt1211_update_client(client); - results[0] = PWM_FROM_REG(data->pwm[nr - 1]); - results[1] = (data->pwm_ctl >> (3 + (4 * (nr - 1)))) & 1; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->pwm[nr - 1] = PWM_TO_REG(results[0]); - if (*nrels_mag >= 2) { - if(results[1]) { - data->pwm_ctl |= - (0x08 << (4 * (nr - 1))); - vt1211_write_value(client, - VT1211_REG_PWM_CTL, - data->pwm_ctl); - } else { - data->pwm_ctl &= - ~ (0x08 << (4 * (nr - 1))); - vt1211_write_value(client, - VT1211_REG_PWM_CTL, - data->pwm_ctl); - } - } - vt1211_write_value(client, VT1211_REG_PWM(nr), - data->pwm[nr - 1]); - } - } -} - -void vt1211_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt1211_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - vt1211_update_client(client); - results[0] = vid_from_reg(data->vid, data->vrm); - *nrels_mag = 1; - } -} - -void vt1211_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt1211_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) - data->vrm = results[0]; - } -} - -void vt1211_uch(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt1211_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->uch_config & 0x7c; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->uch_config = (data->uch_config & 0x83)|(results[0] & 0x7c); - vt1211_write_value(client, VT1211_REG_UCH_CONFIG, - data->uch_config); - } - } -} - -static int __init sm_vt1211_init(void) -{ - int addr; - - printk("vt1211.o version %s (%s)\n", LM_VERSION, LM_DATE); - - if (vt1211_find(&addr)) { - printk("vt1211.o: VT1211 not detected, module not inserted.\n"); - return -ENODEV; - } - normal_isa[0] = addr; - - return i2c_add_driver(&vt1211_driver); -} - -static void __exit sm_vt1211_exit(void) -{ - i2c_del_driver(&vt1211_driver); -} - - - -MODULE_AUTHOR("Mark D. Studebaker "); -MODULE_DESCRIPTION("VT1211 sensors"); -MODULE_LICENSE("GPL"); - -module_init(sm_vt1211_init); -module_exit(sm_vt1211_exit); diff --git a/kernel/chips/vt8231.c b/kernel/chips/vt8231.c deleted file mode 100644 index 24ab2e49..00000000 --- a/kernel/chips/vt8231.c +++ /dev/null @@ -1,836 +0,0 @@ -/* - vt8231.c - Part of lm_sensors, Linux kernel modules - for hardware monitoring - - Copyright (c) 2002 Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* Supports VIA VT8231 South Bridge embedded sensors */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" - - -static int force_addr = 0; -MODULE_PARM(force_addr, "i"); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the sensors"); - -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -SENSORS_INSMOD_1(vt8231); - -#define VIA686A_EXTENT 0x80 -#define VIA686A_BASE_REG 0x70 -#define VIA686A_ENABLE_REG 0x74 - -/* pwm numbered 1-2 */ -#define VT8231_REG_PWM(nr) (0x5f + (nr)) -#define VT8231_REG_PWM_CTL 0x51 - -/* The VT8231 registers */ -/* We define the sensors as follows. - Sensor Voltage Mode Temp Mode - -------- ------------ --------- - Reading 1 temp1 - UCH1 in0 temp2 - UCH2 in1 temp3 - UCH3 in2 temp4 - UCH4 in3 temp5 - UCH5 in4 temp6 - 3.3V in5 -*/ - -/* ins numbered 0-5 */ -#define VT8231_REG_IN_MAX(nr) ((nr)==0 ? 0x3d : 0x29 + ((nr) * 2)) -#define VT8231_REG_IN_MIN(nr) ((nr)==0 ? 0x3e : 0x2a + ((nr) * 2)) -#define VT8231_REG_IN(nr) (0x21 + (nr)) - -/* fans numbered 1-2 */ -#define VT8231_REG_FAN_MIN(nr) (0x3a + (nr)) -#define VT8231_REG_FAN(nr) (0x28 + (nr)) - -static const u8 regtemp[] = { 0x1f, 0x21, 0x22, 0x23, 0x24, 0x25 }; -static const u8 regover[] = { 0x39, 0x3d, 0x2b, 0x2d, 0x2f, 0x31 }; -static const u8 reghyst[] = { 0x3a, 0x3e, 0x2c, 0x2e, 0x30, 0x32 }; - -/* temps numbered 1-6 */ -#define VT8231_REG_TEMP(nr) (regtemp[(nr) - 1]) -#define VT8231_REG_TEMP_OVER(nr) (regover[(nr) - 1]) -#define VT8231_REG_TEMP_HYST(nr) (reghyst[(nr) - 1]) -#define VT8231_REG_TEMP_LOW12 0x49 -#define VT8231_REG_TEMP_LOW36 0x4d - -#define VT8231_REG_CONFIG 0x40 -#define VT8231_REG_ALARM1 0x41 -#define VT8231_REG_ALARM2 0x42 -#define VT8231_REG_VID 0x45 -#define VT8231_REG_FANDIV 0x47 -#define VT8231_REG_UCH_CONFIG 0x4a -#define VT8231_REG_TEMP1_CONFIG 0x4b -#define VT8231_REG_TEMP2_CONFIG 0x4c - -/* temps 1-6; voltages 0-5 */ -#define ISTEMP(i, ch_config) ((i) == 1 ? 1 : \ - ((ch_config) >> (i)) & 0x01) -#define ISVOLT(i, ch_config) ((i) == 5 ? 1 : \ - !(((ch_config) >> ((i)+2)) & 0x01)) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) -#define PWM_FROM_REG(val) (val) -#define PWM_TO_REG(val) SENSORS_LIMIT((val), 0, 255) - -/* Used for temp1 (diode) */ -#define TEMP_FROM_REG(val) ((val)*10) -#define TEMP_FROM_REG10(val) (((val)*10)/4) -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-5)/10):\ - ((val)+5)/10),0,255)) - -/* Used for temp2-temp6 (thermistor) */ -#define THERM_FROM_REG(reg) (((253 * 4 - (reg)) * 55 + 105) / 210) -#define THERM_TO_REG(val) (253 - ((val) * 210 + 110) / 220) - -/* Used for in0-in4 */ -#define IN_FROM_REG(val) ((((val) - 3) * 1000 + 479) / 958) -#define IN_TO_REG(val) SENSORS_LIMIT(((val) * 958 + 500) \ - / 1000 + 3, 0, 255) -/* Used for in5 (scaled internally) */ -#define IN5_FROM_REG(val) ((((val) - 3) * 54000 + 16286) / 32572) -#define IN5_TO_REG(val) SENSORS_LIMIT(((val) * 32572 + 27000) \ - / 54000 + 3, 0, 255) - - -/********* FAN RPM CONVERSIONS ********/ -/* But this chip saturates back at 0, not at 255 like all the other chips. - So, 0 means 0 RPM */ -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 0; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1310720 + rpm * div / 2) / (rpm * div), 1, 255); -} - -#define MIN_TO_REG(a,b) FAN_TO_REG(a,b) -#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1310720/((val)*(div))) - -struct vt8231_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[6]; /* Register value */ - u8 in_max[6]; /* Register value */ - u8 in_min[6]; /* Register value */ - u16 temp[6]; /* Register value 10 bit */ - u8 temp_over[6]; /* Register value */ - u8 temp_hyst[6]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u16 alarms; /* Register encoding */ - u8 pwm[2]; /* Register value */ - u8 pwm_ctl; /* Register value */ - u8 vid; /* Register encoding */ - u8 vrm; - u8 uch_config; -}; - -static int vt8231_attach_adapter(struct i2c_adapter *adapter); -static int vt8231_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int vt8231_detach_client(struct i2c_client *client); - -static inline int vt_rdval(struct i2c_client *client, u8 register); -static inline void vt8231_write_value(struct i2c_client *client, u8 register, - u8 value); -static void vt8231_update_client(struct i2c_client *client); -static void vt8231_init_client(struct i2c_client *client); - - -static void vt8231_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_in5(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_uch(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void vt8231_therm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver vt8231_driver = { - .name = "VT8231 sensors driver", - .id = I2C_DRIVERID_VT8231, - .flags = I2C_DF_NOTIFY, - .attach_adapter = vt8231_attach_adapter, - .detach_client = vt8231_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ -#define VT8231_SYSCTL_IN0 1000 -#define VT8231_SYSCTL_IN1 1001 -#define VT8231_SYSCTL_IN2 1002 -#define VT8231_SYSCTL_IN3 1003 -#define VT8231_SYSCTL_IN4 1004 -#define VT8231_SYSCTL_IN5 1005 -#define VT8231_SYSCTL_FAN1 1101 -#define VT8231_SYSCTL_FAN2 1102 -#define VT8231_SYSCTL_TEMP 1200 -#define VT8231_SYSCTL_TEMP2 1201 -#define VT8231_SYSCTL_TEMP3 1202 -#define VT8231_SYSCTL_TEMP4 1203 -#define VT8231_SYSCTL_TEMP5 1204 -#define VT8231_SYSCTL_TEMP6 1205 -#define VT8231_SYSCTL_VID 1300 -#define VT8231_SYSCTL_PWM1 1401 -#define VT8231_SYSCTL_PWM2 1402 -#define VT8231_SYSCTL_VRM 1600 -#define VT8231_SYSCTL_UCH 1700 -#define VT8231_SYSCTL_FAN_DIV 2000 -#define VT8231_SYSCTL_ALARMS 2001 - -#define VT8231_ALARM_IN1 0x01 -#define VT8231_ALARM_IN2 0x02 -#define VT8231_ALARM_IN5 0x04 -#define VT8231_ALARM_IN3 0x08 -#define VT8231_ALARM_TEMP 0x10 -#define VT8231_ALARM_FAN1 0x40 -#define VT8231_ALARM_FAN2 0x80 -#define VT8231_ALARM_IN4 0x100 -#define VT8231_ALARM_TEMP2 0x800 -#define VT8231_ALARM_CHAS 0x1000 -/* duplicates */ -#define VT8231_ALARM_IN0 VT8231_ALARM_TEMP2 -#define VT8231_ALARM_TEMP3 VT8231_ALARM_IN1 -#define VT8231_ALARM_TEMP4 VT8231_ALARM_IN2 -#define VT8231_ALARM_TEMP5 VT8231_ALARM_IN3 -#define VT8231_ALARM_TEMP6 VT8231_ALARM_IN4 - -/* -- SENSORS SYSCTL END -- */ - -static ctl_table vt8231_dir_table_template[] = { - {VT8231_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_in}, - {VT8231_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_in}, - {VT8231_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_in}, - {VT8231_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_in}, - {VT8231_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_in}, - {VT8231_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_in5}, - {VT8231_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt8231_temp}, - {VT8231_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt8231_therm}, - {VT8231_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt8231_therm}, - {VT8231_SYSCTL_TEMP4, "temp4", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt8231_therm}, - {VT8231_SYSCTL_TEMP5, "temp5", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt8231_therm}, - {VT8231_SYSCTL_TEMP6, "temp6", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &vt8231_therm}, - {VT8231_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_fan}, - {VT8231_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_fan}, - {VT8231_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_fan_div}, - {VT8231_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_alarms}, - {VT8231_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_pwm}, - {VT8231_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_pwm}, - {VT8231_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_vid}, - {VT8231_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_vrm}, - {VT8231_SYSCTL_UCH, "uch_config", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &vt8231_uch}, - {0} -}; - -static struct pci_dev *s_bridge; - -static int vt8231_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, vt8231_detect); -} - -/* Locate chip and get correct base address */ -static int __init vt8231_find(int *address) -{ - u16 val; - - if (!pci_present()) - return -ENODEV; - - if (!(s_bridge = pci_find_device(PCI_VENDOR_ID_VIA, - 0x8235, NULL))) - return -ENODEV; - - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(s_bridge, VIA686A_BASE_REG, &val)) - return -ENODEV; - *address = val & ~(VIA686A_EXTENT - 1); - if (*address == 0 && force_addr == 0) { - printk("vt8231.o: base address not set - upgrade BIOS or use force_addr=0xaddr\n"); - return -ENODEV; - } - if (force_addr) - *address = force_addr; /* so detect will get called */ - - return 0; -} - -int vt8231_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct vt8231_data *data; - int err = 0; - const char *type_name = "vt8231"; - u16 val; - - if (!i2c_is_isa_adapter(adapter)) { - return 0; - } - - /* 8231 requires multiple of 256 */ - if(force_addr) - address = force_addr & 0xFF00; - if (check_region(address, VIA686A_EXTENT)) { - printk("vt8231.o: region 0x%x already in use!\n", - address); - return -ENODEV; - } - - if(force_addr) { - printk("vt8231.o: forcing ISA address 0x%04X\n", address); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(s_bridge, VIA686A_BASE_REG, address)) - return -ENODEV; - } - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val)) - return -ENODEV; - if (!(val & 0x0001)) { - printk("vt8231.o: enabling sensors\n"); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(s_bridge, VIA686A_ENABLE_REG, - val | 0x0001)) - return -ENODEV; - } - - if (!(data = kmalloc(sizeof(struct vt8231_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &vt8231_driver; - new_client->flags = 0; - - /* Reserve the ISA region */ - request_region(address, VIA686A_EXTENT, "vt8231-sensors"); - - /* Fill in the remaining client fields and put into the global list */ - strcpy(new_client->name, "Via 8231 Integrated Sensors"); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry((struct i2c_client *) new_client, - type_name, - vt8231_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - vt8231_init_client(new_client); - return 0; - - ERROR4: - i2c_detach_client(new_client); - ERROR3: - release_region(address, VIA686A_EXTENT); - kfree(data); - ERROR0: - return err; -} - -static int vt8231_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct vt8231_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("vt8231.o: Client deregistration failed, client not detached.\n"); - return err; - } - - release_region(client->addr, VIA686A_EXTENT); - kfree(client->data); - - return 0; -} - - -static inline int vt_rdval(struct i2c_client *client, u8 reg) -{ - return (inb_p(client->addr + reg)); -} - -static inline void vt8231_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - outb_p(value, client->addr + reg); -} - -static void vt8231_init_client(struct i2c_client *client) -{ - struct vt8231_data *data = client->data; - - data->vrm = 91; - /* set "default" interrupt mode for alarms, which isn't the default */ - vt8231_write_value(client, VT8231_REG_TEMP1_CONFIG, 0); - vt8231_write_value(client, VT8231_REG_TEMP2_CONFIG, 0); -} - -static void vt8231_update_client(struct i2c_client *client) -{ - struct vt8231_data *data = client->data; - int i, j; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - data->uch_config = vt_rdval(client, VT8231_REG_UCH_CONFIG); - for (i = 0; i <= 5; i++) { - if(ISVOLT(i, data->uch_config)) { - data->in[i] = vt_rdval(client, VT8231_REG_IN(i)); - data->in_min[i] = vt_rdval(client, - VT8231_REG_IN_MIN(i)); - data->in_max[i] = vt_rdval(client, - VT8231_REG_IN_MAX(i)); - } else { - data->in[i] = 0; - data->in_min[i] = 0; - data->in_max[i] = 0; - } - } - for (i = 1; i <= 2; i++) { - data->fan[i - 1] = vt_rdval(client, VT8231_REG_FAN(i)); - data->fan_min[i - 1] = vt_rdval(client, - VT8231_REG_FAN_MIN(i)); - } - for (i = 1; i <= 6; i++) { - if(ISTEMP(i, data->uch_config)) { - data->temp[i - 1] = vt_rdval(client, - VT8231_REG_TEMP(i)) << 2; - switch(i) { - case 1: - j = (vt_rdval(client, - VT8231_REG_TEMP_LOW12) & - 0xc0) >> 6; - break; - case 2: - j = (vt_rdval(client, - VT8231_REG_TEMP_LOW12) & - 0x30) >> 4; - break; - default: - j = (vt_rdval(client, - VT8231_REG_TEMP_LOW36) >> - ((i-3)*2)) & 0x03; - break; - - } - data->temp[i - 1] |= j; - data->temp_over[i - 1] = vt_rdval(client, - VT8231_REG_TEMP_OVER(i)); - data->temp_hyst[i - 1] = vt_rdval(client, - VT8231_REG_TEMP_HYST(i)); - } else { - data->temp[i - 1] = 0; - data->temp_over[i - 1] = 0; - data->temp_hyst[i - 1] = 0; - } - } - - for (i = 1; i <= 2; i++) { - data->fan[i - 1] = vt_rdval(client, VT8231_REG_FAN(i)); - data->fan_min[i - 1] = vt_rdval(client, - VT8231_REG_FAN_MIN(i)); - data->pwm[i - 1] = vt_rdval(client, VT8231_REG_PWM(i)); - } - - data->pwm_ctl = vt_rdval(client, VT8231_REG_PWM_CTL); - i = vt_rdval(client, VT8231_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = vt_rdval(client, VT8231_REG_ALARM1) | - (vt_rdval(client, VT8231_REG_ALARM2) << 8); - data->vid= vt_rdval(client, VT8231_REG_VID) & 0x1f; - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void vt8231_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - int nr = ctl_name - VT8231_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - vt8231_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0]); - vt8231_write_value(client, VT8231_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1]); - vt8231_write_value(client, VT8231_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void vt8231_in5(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - vt8231_update_client(client); - results[0] = IN5_FROM_REG(data->in_min[5]); - results[1] = IN5_FROM_REG(data->in_max[5]); - results[2] = IN5_FROM_REG(data->in[5]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[5] = IN5_TO_REG(results[0]); - vt8231_write_value(client, VT8231_REG_IN_MIN(5), - data->in_min[5]); - } - if (*nrels_mag >= 2) { - data->in_max[5] = IN5_TO_REG(results[1]); - vt8231_write_value(client, VT8231_REG_IN_MAX(5), - data->in_max[5]); - } - } -} - -void vt8231_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - int nr = ctl_name - VT8231_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - vt8231_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data->fan_div - [nr - 1])); - results[1] = FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = MIN_TO_REG(results[0], - DIV_FROM_REG - (data-> - fan_div[nr-1])); - vt8231_write_value(client, VT8231_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } - } -} - - -void vt8231_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - vt8231_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over[0]); - results[1] = TEMP_FROM_REG(data->temp_hyst[0]); - results[2] = TEMP_FROM_REG10(data->temp[0]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over[0] = TEMP_TO_REG(results[0]); - vt8231_write_value(client, - VT8231_REG_TEMP_OVER(1), - data->temp_over[0]); - } - if (*nrels_mag >= 2) { - data->temp_hyst[0] = TEMP_TO_REG(results[1]); - vt8231_write_value(client, - VT8231_REG_TEMP_HYST(1), - data->temp_hyst[0]); - } - } -} - -void vt8231_therm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - int nr = ctl_name - VT8231_SYSCTL_TEMP; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - vt8231_update_client(client); - results[0] = THERM_FROM_REG(data->temp_over[nr] * 4); - results[1] = THERM_FROM_REG(data->temp_hyst[nr] * 4); - results[2] = THERM_FROM_REG(data->temp[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over[nr] = THERM_TO_REG(results[0]); - vt8231_write_value(client, - VT8231_REG_TEMP_OVER(nr + 1), - data->temp_over[nr]); - } - if (*nrels_mag >= 2) { - data->temp_hyst[nr] = THERM_TO_REG(results[1]); - vt8231_write_value(client, - VT8231_REG_TEMP_HYST(nr + 1), - data->temp_hyst[nr]); - } - } -} - -void vt8231_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - vt8231_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -void vt8231_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - vt8231_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = vt_rdval(client, VT8231_REG_FANDIV); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan_div[1] << 6); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div[0] << 4); - vt8231_write_value(client, VT8231_REG_FANDIV, old); - } - } -} - -void vt8231_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - int nr = 1 + ctl_name - VT8231_SYSCTL_PWM1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - vt8231_update_client(client); - results[0] = PWM_FROM_REG(data->pwm[nr - 1]); - results[1] = (data->pwm_ctl >> (3 + (4 * (nr - 1)))) & 1; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->pwm[nr - 1] = PWM_TO_REG(results[0]); - if (*nrels_mag >= 2) { - if(results[1]) { - data->pwm_ctl |= - (0x08 << (4 * (nr - 1))); - vt8231_write_value(client, - VT8231_REG_PWM_CTL, - data->pwm_ctl); - } else { - data->pwm_ctl &= - ~ (0x08 << (4 * (nr - 1))); - vt8231_write_value(client, - VT8231_REG_PWM_CTL, - data->pwm_ctl); - } - } - vt8231_write_value(client, VT8231_REG_PWM(nr), - data->pwm[nr - 1]); - } - } -} - -void vt8231_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - vt8231_update_client(client); - results[0] = vid_from_reg(data->vid, data->vrm); - *nrels_mag = 1; - } -} - -void vt8231_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) - data->vrm = results[0]; - } -} - -void vt8231_uch(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct vt8231_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->uch_config & 0x7c; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->uch_config = (data->uch_config & 0x83)|(results[0] & 0x7c); - vt8231_write_value(client, VT8231_REG_UCH_CONFIG, - data->uch_config); - } - } -} - -static int __init sm_vt8231_init(void) -{ - int addr; - - printk("vt8231.o version %s (%s)\n", LM_VERSION, LM_DATE); - - if (vt8231_find(&addr)) { - printk("vt8231.o: VT8231 not detected, module not inserted.\n"); - return -ENODEV; - } - normal_isa[0] = addr; - - return i2c_add_driver(&vt8231_driver);} - -static void __exit sm_vt8231_exit(void) -{ - i2c_del_driver(&vt8231_driver); -} - - - -MODULE_AUTHOR("Mark D. Studebaker "); -MODULE_DESCRIPTION("VT8231 sensors"); -MODULE_LICENSE("GPL"); - -module_init(sm_vt8231_init); -module_exit(sm_vt8231_exit); diff --git a/kernel/chips/w83627hf.c b/kernel/chips/w83627hf.c deleted file mode 100644 index f4054615..00000000 --- a/kernel/chips/w83627hf.c +++ /dev/null @@ -1,1501 +0,0 @@ -/* - w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 - 2003 Frodo Looijaard , - Philip Edelbrock , - and Mark Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - Supports following chips: - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - w83627hf 9 3 2 3 0x20 0x5ca3 no yes(LPC) - w83627thf 7 3 3 3 0x90 0x5ca3 no yes(LPC) - w83637hf 7 3 3 3 0x80 0x5ca3 no yes(LPC) - w83687thf 7 3 3 3 0x90 0x5ca3 no yes(LPC) - w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) - - For other winbond chips, and for i2c support in the above chips, - use w83781d.c. - - Note: automatic ("cruise") fan control for 697, 637 & 627thf not - supported yet. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" -#include "lm75.h" - -static int force_addr; -MODULE_PARM(force_addr, "i"); -MODULE_PARM_DESC(force_addr, - "Initialize the base address of the sensors"); -static int force_i2c = 0x1f; -MODULE_PARM(force_i2c, "i"); -MODULE_PARM_DESC(force_i2c, - "Initialize the i2c address of the sensors"); - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_5(w83627hf, w83627thf, w83697hf, w83637hf, w83687thf); - -static int init = 1; -MODULE_PARM(init, "i"); -MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); - -/* modified from kernel/include/traps.c */ -static int REG; /* The register to read/write */ -#define DEV 0x07 /* Register: Logical device select */ -static int VAL; /* The value to read/write */ - -/* logical device numbers for superio_select (below) */ -#define W83627HF_LD_FDC 0x00 -#define W83627HF_LD_PRT 0x01 -#define W83627HF_LD_UART1 0x02 -#define W83627HF_LD_UART2 0x03 -#define W83627HF_LD_KBC 0x05 -#define W83627HF_LD_CIR 0x06 /* w83627hf only */ -#define W83627HF_LD_GAME 0x07 -#define W83627HF_LD_MIDI 0x07 -#define W83627HF_LD_GPIO1 0x07 -#define W83627HF_LD_GPIO5 0x07 /* w83627thf only */ -#define W83627HF_LD_GPIO2 0x08 -#define W83627HF_LD_GPIO3 0x09 -#define W83627HF_LD_GPIO4 0x09 /* w83627thf only */ -#define W83627HF_LD_ACPI 0x0a -#define W83627HF_LD_HWM 0x0b - -#define DEVID 0x20 /* Register: Device ID */ - -#define W83627THF_GPIO5_EN 0x30 /* w83627thf only */ -#define W83627THF_GPIO5_IOSR 0xf3 /* w83627thf only */ -#define W83627THF_GPIO5_DR 0xf4 /* w83627thf only */ - -#define W83687THF_VID_EN 0x29 /* w83687thf only */ -#define W83687THF_VID_CFG 0xF0 /* w83687thf only */ -#define W83687THF_VID_DATA 0xF1 /* w83687thf only */ - -static inline void -superio_outb(int reg, int val) -{ - outb(reg, REG); - outb(val, VAL); -} - -static inline int -superio_inb(int reg) -{ - outb(reg, REG); - return inb(VAL); -} - -static inline void -superio_select(int ld) -{ - outb(DEV, REG); - outb(ld, VAL); -} - -static inline void -superio_enter(void) -{ - outb(0x87, REG); - outb(0x87, REG); -} - -static inline void -superio_exit(void) -{ - outb(0xAA, REG); -} - -#define W627_DEVID 0x52 -#define W627THF_DEVID 0x82 -#define W697_DEVID 0x60 -#define W637_DEVID 0x70 -#define W687THF_DEVID 0x85 -#define WINB_ACT_REG 0x30 -#define WINB_BASE_REG 0x60 -/* Constants specified below */ - -/* Length of ISA address segment */ -#define WINB_EXTENT 8 - -/* Where are the ISA address/data registers relative to the base address */ -#define W83781D_ADDR_REG_OFFSET 5 -#define W83781D_DATA_REG_OFFSET 6 - -/* The W83781D registers */ -/* The W83782D registers for nr=7,8 are in bank 5 */ -#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ - (0x554 + (((nr) - 7) * 2))) -#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ - (0x555 + (((nr) - 7) * 2))) -#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ - (0x550 + (nr) - 7)) - -#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr)) -#define W83781D_REG_FAN(nr) (0x27 + (nr)) - -#define W83781D_REG_TEMP2 0x0150 -#define W83781D_REG_TEMP3 0x0250 -#define W83781D_REG_TEMP2_HYST 0x153 -#define W83781D_REG_TEMP3_HYST 0x253 -#define W83781D_REG_TEMP2_CONFIG 0x152 -#define W83781D_REG_TEMP3_CONFIG 0x252 -#define W83781D_REG_TEMP2_OVER 0x155 -#define W83781D_REG_TEMP3_OVER 0x255 - -#define W83781D_REG_TEMP 0x27 -#define W83781D_REG_TEMP_OVER 0x39 -#define W83781D_REG_TEMP_HYST 0x3A -#define W83781D_REG_BANK 0x4E - -#define W83781D_REG_CONFIG 0x40 -#define W83781D_REG_ALARM1 0x459 -#define W83781D_REG_ALARM2 0x45A -#define W83781D_REG_ALARM3 0x45B - -#define W83781D_REG_BEEP_CONFIG 0x4D -#define W83781D_REG_BEEP_INTS1 0x56 -#define W83781D_REG_BEEP_INTS2 0x57 -#define W83781D_REG_BEEP_INTS3 0x453 - -#define W83781D_REG_VID_FANDIV 0x47 - -#define W83781D_REG_CHIPID 0x49 -#define W83781D_REG_WCHIPID 0x58 -#define W83781D_REG_CHIPMAN 0x4F -#define W83781D_REG_PIN 0x4B - -#define W83781D_REG_VBAT 0x5D - -#define W83627HF_REG_PWM1 0x5A -#define W83627HF_REG_PWM2 0x5B - -#define W83627THF_REG_PWM1 0x01 /* 697HF/637HF/687THF too */ -#define W83627THF_REG_PWM2 0x03 /* 697HF/637HF/687THF too */ -#define W83627THF_REG_PWM3 0x11 /* 637HF/687THF too */ - -#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF/687THF too */ - -static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 }; -static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2, - W83627THF_REG_PWM3 }; -#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \ - regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1]) - -#define W83781D_REG_I2C_ADDR 0x48 -#define W83781D_REG_I2C_SUBADDR 0x4A - -/* Sensor selection */ -#define W83781D_REG_SCFG1 0x5D -static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 }; -#define W83781D_REG_SCFG2 0x59 -static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; -#define W83781D_DEFAULT_BETA 3435 - -/* Conversions. Limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) -#define IN_FROM_REG(val) (((val) * 16 + 5) / 10) - -#define IN_TO_REG_VRM9(val) \ - (SENSORS_LIMIT((((val) * 1000 - 70000 + 244) / 488), 0, 255)) -#define IN_FROM_REG_VRM9(reg) (((reg) * 488 + 70000 + 500) / 1000) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define TEMP_MIN (-1280) -#define TEMP_MAX ( 1270) - -/* TEMP: 1/10 degrees C (-128C to +127C) - REG: 1C/bit, two's complement */ -static u8 TEMP_TO_REG(int temp) -{ - int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX); - ntemp += (ntemp<0 ? -5 : 5); - return (u8)(ntemp / 10); -} - -static int TEMP_FROM_REG(u8 reg) -{ - return (s8)reg * 10; -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) - -#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) -#define BEEPS_TO_REG(val) ((val) & 0xffffff) - -#define BEEP_ENABLE_TO_REG(val) ((val)?1:0) -#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0) - -#define DIV_FROM_REG(val) (1 << (val)) - -static inline u8 DIV_TO_REG(long val) -{ - int i; - val = SENSORS_LIMIT(val, 1, 128) >> 1; - for (i = 0; i < 7; i++) { - if (val == 0) - break; - val >>= 1; - } - return ((u8) i); -} - -/* For each registered chip, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new client is allocated. */ -struct w83627hf_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[9]; /* Register value */ - u8 in_max[9]; /* Register value */ - u8 in_min[9]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 temp; - u8 temp_over; /* Register value */ - u8 temp_hyst; /* Register value */ - u16 temp_add[2]; /* Register value */ - u16 temp_add_over[2]; /* Register value */ - u16 temp_add_hyst[2]; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ - u32 alarms; /* Register encoding, combined */ - u32 beeps; /* Register encoding, combined */ - u8 beep_enable; /* Boolean */ - u8 pwm[3]; /* Register value */ - u16 sens[3]; /* 782D/783S only. - 1 = pentium diode; 2 = 3904 diode; - 3000-5000 = thermistor beta. - Default = 3435. - Other Betas unimplemented */ - u8 vrm; - u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */ -}; - - -static int w83627hf_attach_adapter(struct i2c_adapter *adapter); -static int w83627hf_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int w83627hf_detach_client(struct i2c_client *client); - -static int w83627hf_read_value(struct i2c_client *client, u16 register); -static int w83627hf_write_value(struct i2c_client *client, u16 register, - u16 value); -static void w83627hf_update_client(struct i2c_client *client); -static void w83627hf_init_client(struct i2c_client *client); - - -static void w83627hf_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_beep(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83627hf_sens(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver w83627hf_driver = { - .name = "W83627HF sensor driver", - .id = I2C_DRIVERID_W83627HF, - .flags = I2C_DF_NOTIFY, - .attach_adapter = w83627hf_attach_adapter, - .detach_client = w83627hf_detach_client, -}; - -/* The /proc/sys entries */ -/* WARNING these are copied from w83781d.c and have not been renamed. - Note that the 627hf is supported by both drivers. - Do not make incompatible changes here or we will have errors - in the generated file ../include/sensors.h !!! -*/ -/* -- SENSORS SYSCTL START -- */ - -#define W83781D_SYSCTL_IN0 1000 /* Volts * 100 */ -#define W83781D_SYSCTL_IN1 1001 -#define W83781D_SYSCTL_IN2 1002 -#define W83781D_SYSCTL_IN3 1003 -#define W83781D_SYSCTL_IN4 1004 -#define W83781D_SYSCTL_IN5 1005 -#define W83781D_SYSCTL_IN6 1006 -#define W83781D_SYSCTL_IN7 1007 -#define W83781D_SYSCTL_IN8 1008 -#define W83781D_SYSCTL_FAN1 1101 /* Rotations/min */ -#define W83781D_SYSCTL_FAN2 1102 -#define W83781D_SYSCTL_FAN3 1103 -#define W83781D_SYSCTL_TEMP1 1200 /* Degrees Celsius * 10 */ -#define W83781D_SYSCTL_TEMP2 1201 /* Degrees Celsius * 10 */ -#define W83781D_SYSCTL_TEMP3 1202 /* Degrees Celsius * 10 */ -#define W83781D_SYSCTL_VID 1300 /* Volts * 1000 */ -#define W83781D_SYSCTL_VRM 1301 -#define W83781D_SYSCTL_PWM1 1401 -#define W83781D_SYSCTL_PWM2 1402 -#define W83781D_SYSCTL_PWM3 1403 -#define W83781D_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */ -#define W83781D_SYSCTL_SENS2 1502 -#define W83781D_SYSCTL_SENS3 1503 -#define W83781D_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define W83781D_SYSCTL_ALARMS 2001 /* bitvector */ -#define W83781D_SYSCTL_BEEP 2002 /* bitvector */ - -#define W83781D_ALARM_IN0 0x0001 -#define W83781D_ALARM_IN1 0x0002 -#define W83781D_ALARM_IN2 0x0004 -#define W83781D_ALARM_IN3 0x0008 -#define W83781D_ALARM_IN4 0x0100 -#define W83781D_ALARM_IN5 0x0200 -#define W83781D_ALARM_IN6 0x0400 -#define W83782D_ALARM_IN7 0x10000 -#define W83782D_ALARM_IN8 0x20000 -#define W83781D_ALARM_FAN1 0x0040 -#define W83781D_ALARM_FAN2 0x0080 -#define W83781D_ALARM_FAN3 0x0800 -#define W83781D_ALARM_TEMP1 0x0010 -#define W83781D_ALARM_TEMP23 0x0020 /* 781D only */ -#define W83781D_ALARM_TEMP2 0x0020 /* 782D/783S */ -#define W83781D_ALARM_TEMP3 0x2000 /* 782D only */ -#define W83781D_ALARM_CHAS 0x1000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected chip. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ - -/* without pwm3-4 */ -static ctl_table w83627hf_dir_table_template[] = { - {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan}, - {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan}, - {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan}, - {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_temp}, - {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_temp_add}, - {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_temp_add}, - {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_vid}, - {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_vrm}, - {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan_div}, - {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_alarms}, - {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_beep}, - {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_pwm}, - {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_pwm}, - {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_sens}, - {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_sens}, - {W83781D_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_sens}, - {0} -}; - -/* similar to w83782d but no fan3, no vid */ -static ctl_table w83697hf_dir_table_template[] = { - {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - /* no in1 to maintain compatibility with 781d and 782d. */ - {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan}, - {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan}, - {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_temp}, - {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_temp_add}, - {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan_div}, - {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_alarms}, - {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_beep}, - {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_pwm}, - {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_pwm}, - {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_sens}, - {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_sens}, - {0} -}; - -/* no in5 and in6 */ -/* We use this one for W83637HF and W83687THF too */ -static ctl_table w83627thf_dir_table_template[] = { - {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan}, - {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan}, - {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan}, - {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_temp}, - {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_temp_add}, - {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_temp_add}, - {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_vid}, - {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_vrm}, - {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_fan_div}, - {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_alarms}, - {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_beep}, - {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_pwm}, - {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_pwm}, - {W83781D_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_pwm}, - {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_sens}, - {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_sens}, - {W83781D_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83627hf_sens}, - {0} -}; - - -/* This function is called when: - * w83627hf_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and w83627hf_driver is still present) */ -static int w83627hf_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, w83627hf_detect); -} - -static int __init w83627hf_find(int sioaddr, int *address) -{ - u16 val; - - REG = sioaddr; - VAL = sioaddr + 1; - - superio_enter(); - val= superio_inb(DEVID); - if (val != W627_DEVID && val != W627THF_DEVID && val != W697_DEVID - && val != W637_DEVID && val != W687THF_DEVID) { - superio_exit(); - return -ENODEV; - } - - superio_select(W83627HF_LD_HWM); - val = (superio_inb(WINB_BASE_REG) << 8) | - superio_inb(WINB_BASE_REG + 1); - *address = val & ~(WINB_EXTENT - 1); - if (*address == 0 && force_addr == 0) { - printk("w83627hf.o: base address not set - use force_addr=0xaddr\n"); - superio_exit(); - return -ENODEV; - } - if (force_addr) - *address = force_addr; /* so detect will get called */ - - superio_exit(); - return 0; -} - -int w83627hf_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i, val; - struct i2c_client *new_client; - struct w83627hf_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - if (!i2c_is_isa_adapter(adapter)) - return 0; - - if(force_addr) - address = force_addr & ~(WINB_EXTENT - 1); - if (check_region(address, WINB_EXTENT)) { - printk("w83627hf.o: region 0x%x already in use!\n", address); - return -ENODEV; - } - if(force_addr) { - printk("w83627hf.o: forcing ISA address 0x%04X\n", address); - superio_enter(); - superio_select(W83627HF_LD_HWM); - superio_outb(WINB_BASE_REG, address >> 8); - superio_outb(WINB_BASE_REG+1, address & 0xff); - superio_exit(); - } - - superio_enter(); - val= superio_inb(DEVID); - if(val == W627_DEVID) - kind = w83627hf; - else if(val == W697_DEVID) - kind = w83697hf; - else if(val == W627THF_DEVID) - kind = w83627thf; - else if(val == W637_DEVID) - kind = w83637hf; - else if (val == W687THF_DEVID) - kind = w83687thf; - - superio_select(W83627HF_LD_HWM); - if((val = 0x01 & superio_inb(WINB_ACT_REG)) == 0) - superio_outb(WINB_ACT_REG, 1); - superio_exit(); - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access w83627hf_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &w83627hf_driver; - new_client->flags = 0; - - - if (kind == w83627hf) { - type_name = "w83627hf"; - client_name = "W83627HF chip"; - } else if (kind == w83627thf) { - type_name = "w83627thf"; - client_name = "W83627THF chip"; - } else if (kind == w83697hf) { - type_name = "w83697hf"; - client_name = "W83697HF chip"; - } else if (kind == w83637hf) { - type_name = "w83637hf"; - client_name = "W83637HF chip"; - } else if (kind == w83687thf) { - type_name = "w83687thf"; - client_name = "W83687THF chip"; - } else { - goto ERROR1; - } - - request_region(address, WINB_EXTENT, type_name); - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - (kind == w83697hf) ? - w83697hf_dir_table_template : - (kind == w83627hf) ? - w83627hf_dir_table_template : - /* w83627thf table also used for 637HF - and 687THF */ - w83627thf_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR7; - } - data->sysctl_id = i; - - /* Initialize the chip */ - w83627hf_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - -ERROR7: - i2c_detach_client(new_client); -ERROR3: - release_region(address, WINB_EXTENT); -ERROR1: - kfree(data); -ERROR0: - return err; -} - -static int w83627hf_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct w83627hf_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - (KERN_ERR "w83627hf.o: Client deregistration failed, client not detached.\n"); - return err; - } - - release_region(client->addr, WINB_EXTENT); - kfree(client->data); - - return 0; -} - - -/* - ISA access must always be locked explicitly! - We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, - would slow down the W83781D access and should not be necessary. - There are some ugly typecasts here, but the good news is - they should - nowhere else be necessary! */ -static int w83627hf_read_value(struct i2c_client *client, u16 reg) -{ - int res, word_sized; - - down(&(((struct w83627hf_data *) (client->data))->lock)); - word_sized = (((reg & 0xff00) == 0x100) - || ((reg & 0xff00) == 0x200)) - && (((reg & 0x00ff) == 0x50) - || ((reg & 0x00ff) == 0x53) - || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - } - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); - res = inb_p(client->addr + W83781D_DATA_REG_OFFSET); - if (word_sized) { - outb_p((reg & 0xff) + 1, - client->addr + W83781D_ADDR_REG_OFFSET); - res = - (res << 8) + inb_p(client->addr + - W83781D_DATA_REG_OFFSET); - } - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); - } - up(&(((struct w83627hf_data *) (client->data))->lock)); - return res; -} - -static int w83627thf_read_gpio5(struct i2c_client *client) -{ - int res = 0xff, sel; - - superio_enter(); - superio_select(W83627HF_LD_GPIO5); - - /* Make sure these GPIO pins are enabled */ - if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) { -#ifdef DEBUG - printk(KERN_DEBUG "w83627hf: GPIO5 disabled, no VID " - "function\n"); -#endif - goto exit; - } - - /* Make sure the pins are configured for input - There must be at least five (VRM 9), and possibly 6 (VRM 10) */ - sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f; - if ((sel & 0x1f) != 0x1f) { -#ifdef DEBUG - printk(KERN_DEBUG "w83627hf: GPIO5 not configured for " - "VID function\n"); -#endif - goto exit; - } - - printk(KERN_INFO "w83627hf: Reading VID from GPIO5\n"); - res = superio_inb(W83627THF_GPIO5_DR) & sel; - -exit: - superio_exit(); - return res; -} - -static int w83687thf_read_vid(struct i2c_client *client) -{ - int res = 0xff; - - superio_enter(); - superio_select(W83627HF_LD_HWM); - - /* Make sure these GPIO pins are enabled */ - if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) { -#ifdef DEBUG - printk(KERN_DEBUG "w83627hf: VID disabled, no VID " - "function\n"); -#endif - goto exit; - } - - /* Make sure the pins are configured for input */ - if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) { -#ifdef DEBUG - printk(KERN_DEBUG "w83627hf: VID configured as output, " - "no VID function\n"); -#endif - goto exit; - } - - res = superio_inb(W83687THF_VID_DATA) & 0x3f; - -exit: - superio_exit(); - return res; -} - -static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value) -{ - int word_sized; - - down(&(((struct w83627hf_data *) (client->data))->lock)); - word_sized = (((reg & 0xff00) == 0x100) - || ((reg & 0xff00) == 0x200)) - && (((reg & 0x00ff) == 0x53) - || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - } - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); - if (word_sized) { - outb_p(value >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - outb_p((reg & 0xff) + 1, - client->addr + W83781D_ADDR_REG_OFFSET); - } - outb_p(value & 0xff, - client->addr + W83781D_DATA_REG_OFFSET); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); - } - up(&(((struct w83627hf_data *) (client->data))->lock)); - return 0; -} - -/* Called when we have found a new W83781D. */ -static void w83627hf_init_client(struct i2c_client *client) -{ - struct w83627hf_data *data = client->data; - int i; - int type = data->type; - u8 tmp; - - /* Minimize conflicts with other winbond i2c-only clients... */ - /* disable i2c subclients... how to disable main i2c client?? */ - /* force i2c address to relatively uncommon address */ - w83627hf_write_value(client, W83781D_REG_I2C_SUBADDR, 0x89); - w83627hf_write_value(client, W83781D_REG_I2C_ADDR, force_i2c); - - /* Read VID only once */ - if (w83627hf == data->type || w83637hf == data->type) { - int lo = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); - int hi = w83627hf_read_value(client, W83781D_REG_CHIPID); - data->vid = (lo & 0x0f) | ((hi & 0x01) << 4); - } else if (w83627thf == data->type) { - data->vid = w83627thf_read_gpio5(client); - } else if (w83687thf == data->type) { - data->vid = w83687thf_read_vid(client); - } - - /* Read VRM & OVT Config only once */ - if (w83627thf == data->type || w83637hf == data->type - || w83687thf == data->type) - data->vrm_ovt = - w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG); - else - data->vrm_ovt = 0; - - /* Choose VRM based on "VRM & OVT" register */ - data->vrm = (data->vrm_ovt & 0x01) ? 90 : 82; - - tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); - for (i = 1; i <= 3; i++) { - if (!(tmp & BIT_SCFG1[i - 1])) { - data->sens[i - 1] = W83781D_DEFAULT_BETA; - } else { - if (w83627hf_read_value - (client, - W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) - data->sens[i - 1] = 1; - else - data->sens[i - 1] = 2; - } - if ((type == w83697hf) && (i == 2)) - break; - } - - if(init) { - /* Enable temp2 */ - tmp = w83627hf_read_value(client, W83781D_REG_TEMP2_CONFIG); - if (tmp & 0x01) { - printk(KERN_WARNING "w83627hf: temp2 was disabled, " - "readings might not make sense\n"); - w83627hf_write_value(client, W83781D_REG_TEMP2_CONFIG, - tmp & 0xfe); - } - - /* Enable temp3 */ - if (type != w83697hf) { - tmp = w83627hf_read_value(client, - W83781D_REG_TEMP3_CONFIG); - if (tmp & 0x01) { - printk(KERN_WARNING "w83627hf: temp3 was " - "disabled, readings might not make " - "sense\n"); - w83627hf_write_value(client, - W83781D_REG_TEMP3_CONFIG, tmp & 0xfe); - } - } - } - - /* Start monitoring */ - w83627hf_write_value(client, W83781D_REG_CONFIG, - (w83627hf_read_value(client, - W83781D_REG_CONFIG) & 0xf7) - | 0x01); -} - -static void w83627hf_update_client(struct i2c_client *client) -{ - struct w83627hf_data *data = client->data; - int i; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - for (i = 0; i <= 8; i++) { - /* skip missing sensors */ - if (((data->type == w83697hf) && (i == 1)) || - ((data->type == w83627thf || data->type == w83637hf - || data->type == w83687thf) && (i == 5 || i == 6))) - continue; - data->in[i] = - w83627hf_read_value(client, W83781D_REG_IN(i)); - data->in_min[i] = - w83627hf_read_value(client, - W83781D_REG_IN_MIN(i)); - data->in_max[i] = - w83627hf_read_value(client, - W83781D_REG_IN_MAX(i)); - } - for (i = 1; i <= 3; i++) { - data->fan[i - 1] = - w83627hf_read_value(client, W83781D_REG_FAN(i)); - data->fan_min[i - 1] = - w83627hf_read_value(client, - W83781D_REG_FAN_MIN(i)); - } - for (i = 1; i <= 3; i++) { - u8 tmp = w83627hf_read_value(client, - W836X7HF_REG_PWM(data->type, i)); - if (data->type == w83627thf) - tmp &= 0xf0; /* bits 0-3 are reserved in 627THF */ - data->pwm[i - 1] = tmp; - if(i == 2 && (data->type == w83627hf || data->type == w83697hf)) - break; - } - - data->temp = w83627hf_read_value(client, W83781D_REG_TEMP); - data->temp_over = - w83627hf_read_value(client, W83781D_REG_TEMP_OVER); - data->temp_hyst = - w83627hf_read_value(client, W83781D_REG_TEMP_HYST); - data->temp_add[0] = - w83627hf_read_value(client, W83781D_REG_TEMP2); - data->temp_add_over[0] = - w83627hf_read_value(client, W83781D_REG_TEMP2_OVER); - data->temp_add_hyst[0] = - w83627hf_read_value(client, W83781D_REG_TEMP2_HYST); - if (data->type != w83697hf) { - data->temp_add[1] = - w83627hf_read_value(client, W83781D_REG_TEMP3); - data->temp_add_over[1] = - w83627hf_read_value(client, W83781D_REG_TEMP3_OVER); - data->temp_add_hyst[1] = - w83627hf_read_value(client, W83781D_REG_TEMP3_HYST); - } - - i = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - if (data->type != w83697hf) { - data->fan_div[2] = (w83627hf_read_value(client, - W83781D_REG_PIN) >> 6) & 0x03; - } - i = w83627hf_read_value(client, W83781D_REG_VBAT); - data->fan_div[0] |= (i >> 3) & 0x04; - data->fan_div[1] |= (i >> 4) & 0x04; - if (data->type != w83697hf) - data->fan_div[2] |= (i >> 5) & 0x04; - data->alarms = - w83627hf_read_value(client, W83781D_REG_ALARM1) | - (w83627hf_read_value(client, W83781D_REG_ALARM2) << 8) | - (w83627hf_read_value(client, W83781D_REG_ALARM3) << 16); - i = w83627hf_read_value(client, W83781D_REG_BEEP_INTS2); - data->beep_enable = i >> 7; - data->beeps = ((i & 0x7f) << 8) | - w83627hf_read_value(client, W83781D_REG_BEEP_INTS1) | - w83627hf_read_value(client, W83781D_REG_BEEP_INTS3) << 16; - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -void w83627hf_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - int nr = ctl_name - W83781D_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627hf_update_client(client); - - if (nr == 0 && (data->vrm_ovt & 0x01)) { - /* use VRM9 calculation */ - results[0] = IN_FROM_REG_VRM9(data->in_min[0]); - results[1] = IN_FROM_REG_VRM9(data->in_max[0]); - results[2] = IN_FROM_REG_VRM9(data->in[0]); - - } else { - /* use VRM8 (standard) calculation */ - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - } - - *nrels_mag = 3; - - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (nr == 0 && (data->vrm_ovt & 0x01)) - /* use VRM9 calculation */ - data->in_min[0] = IN_TO_REG_VRM9(results[0]); - else - /* use VRM8 (standard) calculation */ - data->in_min[nr] = IN_TO_REG(results[0]); - - w83627hf_write_value(client, W83781D_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - if (nr == 0 && (data->vrm_ovt & 0x01)) - /* use VRM9 calculation */ - data->in_max[0] = IN_TO_REG_VRM9(results[1]); - else - /* use VRM8 (standard) calculation */ - data->in_max[nr] = IN_TO_REG(results[1]); - - w83627hf_write_value(client, W83781D_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void w83627hf_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - int nr = ctl_name - W83781D_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627hf_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - results[1] = FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = - FAN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr-1])); - w83627hf_write_value(client, - W83781D_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } - } -} - -void w83627hf_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627hf_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over = TEMP_TO_REG(results[0]); - w83627hf_write_value(client, W83781D_REG_TEMP_OVER, - data->temp_over); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - w83627hf_write_value(client, W83781D_REG_TEMP_HYST, - data->temp_hyst); - } - } -} - -void w83627hf_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - int nr = ctl_name - W83781D_SYSCTL_TEMP2; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627hf_update_client(client); - results[0] = - LM75_TEMP_FROM_REG(data->temp_add_over[nr]); - results[1] = - LM75_TEMP_FROM_REG(data->temp_add_hyst[nr]); - results[2] = LM75_TEMP_FROM_REG(data->temp_add[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_add_over[nr] = - LM75_TEMP_TO_REG(results[0]); - w83627hf_write_value(client, - nr ? W83781D_REG_TEMP3_OVER : - W83781D_REG_TEMP2_OVER, - data->temp_add_over[nr]); - } - if (*nrels_mag >= 2) { - data->temp_add_hyst[nr] = - LM75_TEMP_TO_REG(results[1]); - w83627hf_write_value(client, - nr ? W83781D_REG_TEMP3_HYST : - W83781D_REG_TEMP2_HYST, - data->temp_add_hyst[nr]); - } - } -} - -void w83627hf_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - if (data->vid == 0xff) - results[0] = 0; - else - results[0] = vid_from_reg(data->vid, data->vrm); - *nrels_mag = 1; - } -} - -void w83627hf_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) - data->vrm = results[0]; - } -} - -void w83627hf_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627hf_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -void w83627hf_beep(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - int val; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627hf_update_client(client); - results[0] = BEEP_ENABLE_FROM_REG(data->beep_enable); - results[1] = data->beeps; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 2) { - data->beeps = BEEPS_TO_REG(results[1]); - w83627hf_write_value(client, W83781D_REG_BEEP_INTS1, - data->beeps & 0xff); - w83627hf_write_value(client, - W83781D_REG_BEEP_INTS3, - ((data-> beeps) >> 16) & - 0xff); - val = (data->beeps >> 8) & 0x7f; - } else if (*nrels_mag >= 1) - val = - w83627hf_read_value(client, - W83781D_REG_BEEP_INTS2) & - 0x7f; - if (*nrels_mag >= 1) { - data->beep_enable = BEEP_ENABLE_TO_REG(results[0]); - w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, - val | data->beep_enable << 7); - } - } -} - -/* w83697hf only has two fans */ -void w83627hf_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - int old, old2, old3 = 0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627hf_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - if (data->type == w83697hf) { - *nrels_mag = 2; - } else { - results[2] = DIV_FROM_REG(data->fan_div[2]); - *nrels_mag = 3; - } - } else if (operation == SENSORS_PROC_REAL_WRITE) { - unsigned long min = 0; - - old = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); - /* w83627hf doesn't have extended divisor bits */ - old3 = w83627hf_read_value(client, W83781D_REG_VBAT); - if (*nrels_mag >= 3 && data->type != w83697hf) { - min = FAN_FROM_REG(data->fan_min[2], - DIV_FROM_REG(data->fan_div[2])); - data->fan_div[2] = DIV_TO_REG(results[2]); - old2 = w83627hf_read_value(client, W83781D_REG_PIN); - old2 = (old2 & 0x3f) - | ((data->fan_div[2] & 0x03) << 6); - w83627hf_write_value(client, W83781D_REG_PIN, old2); - old3 = (old3 & 0x7f) - | ((data->fan_div[2] & 0x04) << 5); - data->fan_min[2] = FAN_TO_REG(min, - DIV_FROM_REG(data->fan_div[2])); - w83627hf_write_value(client, W83781D_REG_FAN_MIN(3), - data->fan_min[2]); - } - if (*nrels_mag >= 2) { - min = FAN_FROM_REG(data->fan_min[1], - DIV_FROM_REG(data->fan_div[1])); - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) - | ((data->fan_div[1] & 0x03) << 6); - old3 = (old3 & 0xbf) - | ((data->fan_div[1] & 0x04) << 4); - data->fan_min[1] = FAN_TO_REG(min, - DIV_FROM_REG(data->fan_div[1])); - w83627hf_write_value(client, W83781D_REG_FAN_MIN(2), - data->fan_min[1]); - } - if (*nrels_mag >= 1) { - min = FAN_FROM_REG(data->fan_min[0], - DIV_FROM_REG(data->fan_div[0])); - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) - | ((data->fan_div[0] & 0x03) << 4); - w83627hf_write_value(client, W83781D_REG_VID_FANDIV, - old); - old3 = (old3 & 0xdf) - | ((data->fan_div[0] & 0x04) << 3); - w83627hf_write_value(client, W83781D_REG_VBAT, - old3); - data->fan_min[0] = FAN_TO_REG(min, - DIV_FROM_REG(data->fan_div[0])); - w83627hf_write_value(client, W83781D_REG_FAN_MIN(1), - data->fan_min[0]); - } - } -} - -/* we do not currently support disabling PWM with 2nd argument; - set first argument to 255 to disable */ -void w83627hf_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - int nr = 1 + ctl_name - W83781D_SYSCTL_PWM1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83627hf_update_client(client); - results[0] = data->pwm[nr - 1]; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - if (data->type == w83627thf) { - /* bits 0-3 are reserved in 627THF */ - data->pwm[nr - 1] = PWM_TO_REG(results[0]) & 0xf0; - w83627hf_write_value(client, - W836X7HF_REG_PWM(data->type, nr), - data->pwm[nr - 1] | - (w83627hf_read_value(client, - W836X7HF_REG_PWM(data->type, nr)) & 0x0f)); - } else { - data->pwm[nr - 1] = PWM_TO_REG(results[0]); - w83627hf_write_value(client, - W836X7HF_REG_PWM(data->type, nr), - data->pwm[nr - 1]); - } - } - } -} - -void w83627hf_sens(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83627hf_data *data = client->data; - int nr = 1 + ctl_name - W83781D_SYSCTL_SENS1; - u8 tmp; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->sens[nr - 1]; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - switch (results[0]) { - case 1: /* PII/Celeron diode */ - tmp = w83627hf_read_value(client, - W83781D_REG_SCFG1); - w83627hf_write_value(client, - W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - - 1]); - tmp = w83627hf_read_value(client, - W83781D_REG_SCFG2); - w83627hf_write_value(client, - W83781D_REG_SCFG2, - tmp | BIT_SCFG2[nr - - 1]); - data->sens[nr - 1] = results[0]; - break; - case 2: /* 3904 */ - tmp = w83627hf_read_value(client, - W83781D_REG_SCFG1); - w83627hf_write_value(client, - W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - - 1]); - tmp = w83627hf_read_value(client, - W83781D_REG_SCFG2); - w83627hf_write_value(client, - W83781D_REG_SCFG2, - tmp & ~BIT_SCFG2[nr - - 1]); - data->sens[nr - 1] = results[0]; - break; - case W83781D_DEFAULT_BETA: /* thermistor */ - tmp = w83627hf_read_value(client, - W83781D_REG_SCFG1); - w83627hf_write_value(client, - W83781D_REG_SCFG1, - tmp & ~BIT_SCFG1[nr - - 1]); - data->sens[nr - 1] = results[0]; - break; - default: - printk - (KERN_ERR "w83627hf.o: Invalid sensor type %ld; must be 1, 2, or %d\n", - results[0], W83781D_DEFAULT_BETA); - break; - } - } - } -} - -static int __init sm_w83627hf_init(void) -{ - int addr; - - printk(KERN_INFO "w83627hf.o version %s (%s)\n", LM_VERSION, LM_DATE); - if (w83627hf_find(0x2e, &addr) - && w83627hf_find(0x4e, &addr)) { - printk("w83627hf.o: W83627/697 not detected, module not inserted.\n"); - return -ENODEV; - } - normal_isa[0] = addr; - - return i2c_add_driver(&w83627hf_driver); -} - -static void __exit sm_w83627hf_exit(void) -{ - i2c_del_driver(&w83627hf_driver); -} - - - -MODULE_AUTHOR("Frodo Looijaard , " - "Philip Edelbrock , " - "and Mark Studebaker "); -MODULE_DESCRIPTION("W83627HF driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_w83627hf_init); -module_exit(sm_w83627hf_exit); diff --git a/kernel/chips/w83781d.c b/kernel/chips/w83781d.c deleted file mode 100644 index 73ceec28..00000000 --- a/kernel/chips/w83781d.c +++ /dev/null @@ -1,1883 +0,0 @@ -/* - w83781d.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 - 2003 Frodo Looijaard , - Philip Edelbrock , - and Mark Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - Supports following chips: - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - as99127f 7 3 0 3 0x31 0x12c3 yes no - as99127f rev.2 (type name = as99127f) 0x31 0x5ca3 yes no - w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC) - w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes - w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes - w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no - w83791d 10 5 5 3 0x71 0x5ca3 yes no - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" -#include "lm75.h" - -/* RT Table support #defined so we can take it out if it gets bothersome */ -#define W83781D_RT 1 - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x20, 0x2f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { 0x0290, SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_6(w83781d, w83782d, w83783s, w83627hf, as99127f, w83791d); -SENSORS_MODULE_PARM(force_subclients, "List of subclient addresses: " \ - "{bus, clientaddr, subclientaddr1, subclientaddr2}"); - -static int init = 1; -MODULE_PARM(init, "i"); -MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); - -/* Constants specified below */ - -/* Length of ISA address segment */ -#define W83781D_EXTENT 8 - -/* Where are the ISA address/data registers relative to the base address */ -#define W83781D_ADDR_REG_OFFSET 5 -#define W83781D_DATA_REG_OFFSET 6 - -/* The W83781D registers */ -/* The W83782D registers for nr=7,8 are in bank 5 */ -#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ - (0x554 + (((nr) - 7) * 2))) -#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ - (0x555 + (((nr) - 7) * 2))) -#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ - (0x550 + (nr) - 7)) - -#define W83791D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ - (0xb4 + (((nr) - 7) * 2))) -#define W83791D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ - (0xb5 + (((nr) - 7) * 2))) -#define W83791D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ - (0xb0 + (nr) - 7)) - -#define W83781D_REG_FAN_MIN(nr) ((nr < 4) ? (0x3a + (nr)) : \ - (0xba + (nr) - 4)) -#define W83781D_REG_FAN(nr) ((nr < 4) ? (0x27 + (nr)) : \ - (0xbc + (nr) - 4)) - -#define W83781D_REG_TEMP2 0x0150 -#define W83781D_REG_TEMP3 0x0250 -#define W83781D_REG_TEMP2_HYST 0x153 -#define W83781D_REG_TEMP3_HYST 0x253 -#define W83781D_REG_TEMP2_CONFIG 0x152 -#define W83781D_REG_TEMP3_CONFIG 0x252 -#define W83781D_REG_TEMP2_OVER 0x155 -#define W83781D_REG_TEMP3_OVER 0x255 - -#define W83781D_REG_TEMP 0x27 -#define W83781D_REG_TEMP_OVER 0x39 -#define W83781D_REG_TEMP_HYST 0x3A -#define W83781D_REG_BANK 0x4E - -#define W83781D_REG_CONFIG 0x40 - -/* Interrupt status (W83781D, AS99127F) */ -#define W83781D_REG_ALARM1 0x41 -#define W83781D_REG_ALARM2 0x42 - -/* Real-time status (W83782D, W83783S, W83627HF) */ -#define W83782D_REG_ALARM1 0x459 -#define W83782D_REG_ALARM2 0x45A -#define W83782D_REG_ALARM3 0x45B - -/* Real-time status (W83791D) */ -#define W83791D_REG_ALARM1 0xA9 -#define W83791D_REG_ALARM2 0xAA -#define W83791D_REG_ALARM3 0xAB - -#define W83781D_REG_BEEP_CONFIG 0x4D -#define W83781D_REG_BEEP_INTS1 0x56 -#define W83781D_REG_BEEP_INTS2 0x57 -#define W83781D_REG_BEEP_INTS3 0x453 /* not on W83781D */ - -#define W83781D_REG_VID_FANDIV 0x47 - -#define W83781D_REG_CHIPID 0x49 -#define W83781D_REG_WCHIPID 0x58 -#define W83781D_REG_CHIPMAN 0x4F -#define W83781D_REG_PIN 0x4B - -/* 782D/783S/791D only */ -#define W83781D_REG_VBAT 0x5D - -/* PWM 782D (1-4) and 783S (1-2) only */ -#define W83781D_REG_PWM1 0x5B /* 782d and 783s/627hf datasheets disagree */ - /* on which is which; */ -#define W83781D_REG_PWM2 0x5A /* We follow the 782d convention here, */ - /* However 782d is probably wrong. */ -#define W83781D_REG_PWM3 0x5E -#define W83781D_REG_PWM4 0x5F -#define W83781D_REG_PWMCLK12 0x5C -#define W83781D_REG_PWMCLK34 0x45C - -#define W83791D_REG_PWM1 0x81 -#define W83791D_REG_PWM2 0x83 -#define W83791D_REG_PWM3 0x94 - -#define W83627HF_REG_PWM1 0x01 -#define W83627HF_REG_PWM2 0x03 -#define W83627HF_REG_PWMCLK1 0x00 -#define W83627HF_REG_PWMCLK2 0x02 - -static const u8 regpwm[] = { W83781D_REG_PWM1, W83781D_REG_PWM2, - W83781D_REG_PWM3, W83781D_REG_PWM4 -}; - -static const u8 regpwm_w83791d[] = { W83791D_REG_PWM1, W83791D_REG_PWM2, - W83791D_REG_PWM3 -}; - -#define W83781D_REG_PWM(type, nr) (((type) == w83791d) ? \ - regpwm_w83791d[(nr) - 1] : \ - regpwm[(nr) - 1]) - -#define W83781D_REG_I2C_ADDR 0x48 -#define W83781D_REG_I2C_SUBADDR 0x4A - -/* The following are undocumented in the data sheets however we - received the information in an email from Winbond tech support */ -/* Sensor selection - not on 781d */ -#define W83781D_REG_SCFG1 0x5D -static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 }; -#define W83781D_REG_SCFG2 0x59 -static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; -#define W83781D_DEFAULT_BETA 3435 - -/* RT Table registers */ -#define W83781D_REG_RT_IDX 0x50 -#define W83781D_REG_RT_VAL 0x51 - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) -#define IN_FROM_REG(val) (((val) * 16 + 5) / 10) - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); -} - -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) - -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-5)/10):\ - ((val)+5)/10),0,255)) -#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10) - -#define ALARMS_FROM_REG(val) (val) -#define PWM_FROM_REG(val) (val) -#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) -#define BEEPS_FROM_REG(val,type) ((type)==as99127f?(val)^0x7FFF:(val)) -#define BEEPS_TO_REG(val,type) ((type)==as99127f?(~(val))&0x7FFF:(val)&0xffffff) - -#define BEEP_ENABLE_TO_REG(val) ((val)?1:0) -#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0) - -#define DIV_FROM_REG(val) (1 << (val)) - -static inline u8 DIV_TO_REG(long val, enum chips type) -{ - int i; - val = SENSORS_LIMIT(val, 1, - ((type == w83781d || type == as99127f) ? 8 : 128)) >> 1; - for (i = 0; i < 7; i++) { - if (val == 0) - break; - val >>= 1; - } - return ((u8) i); -} - -/* There are some complications in a module like this. First off, W83781D chips - may be both present on the SMBus and the ISA bus, and we have to handle - those cases separately at some places. Second, there might be several - W83781D chips available (well, actually, that is probably never done; but - it is a clean illustration of how to handle a case like that). Finally, - a specific chip may be attached to *both* ISA and SMBus, and we would - not like to detect it double. Fortunately, in the case of the W83781D at - least, a register tells us what SMBus address we are on, so that helps - a bit - except if there could be more than one SMBus. Groan. No solution - for this yet. */ - -/* This module may seem overly long and complicated. In fact, it is not so - bad. Quite a lot of bookkeeping is done. A real driver can often cut - some corners. */ - -/* For each registered W83781D, we need to keep some data in memory. It is - dynamically allocated, at the same time when a new w83781d client is - allocated. */ -struct w83781d_data { - struct i2c_client client; - struct semaphore lock; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - struct i2c_client *lm75; /* for secondary I2C addresses */ - /* pointer to array of 2 subclients */ - - u8 in[10]; /* Register value - 8 & 9 for 782D and 791D only 10 for 791D */ - u8 in_max[10]; /* Register value - 8 & 9 for 782D and 791D only 10 for 791D */ - u8 in_min[10]; /* Register value - 8 & 9 for 782D and 791D only 10 for 791D */ - u8 fan[5]; /* Register value - 4 & 5 for 791D only */ - u8 fan_min[5]; /* Register value - 4 & 5 for 791D only */ - u8 temp; - u8 temp_over; /* Register value */ - u8 temp_hyst; /* Register value */ - u16 temp_add[2]; /* Register value */ - u16 temp_add_over[2]; /* Register value */ - u16 temp_add_hyst[2]; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ - u32 alarms; /* Register encoding, combined */ - u32 beeps; /* Register encoding, combined */ - u8 beep_enable; /* Boolean */ - u8 pwm[4]; /* Register value */ - u8 pwmenable[4]; /* bool */ - u16 sens[3]; /* 782D/783S only. - 1 = pentium diode; 2 = 3904 diode; - 3000-5000 = thermistor beta. - Default = 3435. - Other Betas unimplemented */ -#ifdef W83781D_RT - u8 rt[3][32]; /* Register value */ -#endif - u8 vrm; -}; - - -static int w83781d_attach_adapter(struct i2c_adapter *adapter); -static int w83781d_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int w83781d_detach_client(struct i2c_client *client); - -static int w83781d_read_value(struct i2c_client *client, u16 register); -static int w83781d_write_value(struct i2c_client *client, u16 register, - u16 value); -static void w83781d_update_client(struct i2c_client *client); -static void w83781d_init_client(struct i2c_client *client); - - -static void w83781d_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_beep(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_sens(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -#ifdef W83781D_RT -static void w83781d_rt(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -#endif - -static struct i2c_driver w83781d_driver = { - .name = "W83781D sensor driver", - .id = I2C_DRIVERID_W83781D, - .flags = I2C_DF_NOTIFY, - .attach_adapter = w83781d_attach_adapter, - .detach_client = w83781d_detach_client, -}; - -/* The /proc/sys entries */ -/* -- SENSORS SYSCTL START -- */ - -#define W83781D_SYSCTL_IN0 1000 /* Volts * 100 */ -#define W83781D_SYSCTL_IN1 1001 -#define W83781D_SYSCTL_IN2 1002 -#define W83781D_SYSCTL_IN3 1003 -#define W83781D_SYSCTL_IN4 1004 -#define W83781D_SYSCTL_IN5 1005 -#define W83781D_SYSCTL_IN6 1006 -#define W83781D_SYSCTL_IN7 1007 -#define W83781D_SYSCTL_IN8 1008 -#define W83781D_SYSCTL_IN9 1009 -#define W83781D_SYSCTL_FAN1 1101 /* Rotations/min */ -#define W83781D_SYSCTL_FAN2 1102 -#define W83781D_SYSCTL_FAN3 1103 -#define W83781D_SYSCTL_FAN4 1104 -#define W83781D_SYSCTL_FAN5 1105 - -#define W83781D_SYSCTL_TEMP1 1200 /* Degrees Celsius * 10 */ -#define W83781D_SYSCTL_TEMP2 1201 /* Degrees Celsius * 10 */ -#define W83781D_SYSCTL_TEMP3 1202 /* Degrees Celsius * 10 */ -#define W83781D_SYSCTL_VID 1300 /* Volts * 1000 */ -#define W83781D_SYSCTL_VRM 1301 -#define W83781D_SYSCTL_PWM1 1401 -#define W83781D_SYSCTL_PWM2 1402 -#define W83781D_SYSCTL_PWM3 1403 -#define W83781D_SYSCTL_PWM4 1404 -#define W83781D_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */ -#define W83781D_SYSCTL_SENS2 1502 -#define W83781D_SYSCTL_SENS3 1503 -#define W83781D_SYSCTL_RT1 1601 /* 32-entry table */ -#define W83781D_SYSCTL_RT2 1602 /* 32-entry table */ -#define W83781D_SYSCTL_RT3 1603 /* 32-entry table */ -#define W83781D_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define W83781D_SYSCTL_ALARMS 2001 /* bitvector */ -#define W83781D_SYSCTL_BEEP 2002 /* bitvector */ - -#define W83781D_ALARM_IN0 0x0001 -#define W83781D_ALARM_IN1 0x0002 -#define W83781D_ALARM_IN2 0x0004 -#define W83781D_ALARM_IN3 0x0008 -#define W83781D_ALARM_IN4 0x0100 -#define W83781D_ALARM_IN5 0x0200 -#define W83781D_ALARM_IN6 0x0400 -#define W83782D_ALARM_IN7 0x10000 -#define W83782D_ALARM_IN8 0x20000 -#define W83791D_ALARM_IN7 0x080000 /* 791D only */ -#define W83791D_ALARM_IN8 0x100000 /* 791D only */ -#define W83791D_ALARM_IN9 0x004000 /* 791D only */ -#define W83781D_ALARM_FAN1 0x0040 -#define W83781D_ALARM_FAN2 0x0080 -#define W83781D_ALARM_FAN3 0x0800 -#define W83791D_ALARM_FAN4 0x200000 /* 791D only */ -#define W83791D_ALARM_FAN5 0x400000 /* 791D only */ -#define W83781D_ALARM_TEMP1 0x0010 -#define W83781D_ALARM_TEMP23 0x0020 /* 781D only */ -#define W83781D_ALARM_TEMP2 0x0020 /* 782D/783S/791D */ -#define W83781D_ALARM_TEMP3 0x2000 /* 782D/791D */ -#define W83781D_ALARM_CHAS 0x1000 /* 782D/791D */ - -#define W83791D_BEEP_IN1 0x002000 /* 791D only */ -#define W83791D_BEEP_IN7 0x010000 /* 791D only */ -#define W83791D_BEEP_IN8 0x020000 /* 791D only */ -#define W83791D_BEEP_TEMP3 0x000002 /* 791D only */ - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected chip. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ - -/* just a guess - no datasheet */ -static ctl_table as99127f_dir_table_template[] = { - {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp}, - {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vid}, - {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vrm}, - {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan_div}, - {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_alarms}, - {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_beep}, - {0} -}; - -static ctl_table w83781d_dir_table_template[] = { - {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp}, - {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vid}, - {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vrm}, - {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan_div}, - {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_alarms}, - {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_beep}, -#ifdef W83781D_RT - {W83781D_SYSCTL_RT1, "rt1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_rt}, - {W83781D_SYSCTL_RT2, "rt2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_rt}, - {W83781D_SYSCTL_RT3, "rt3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_rt}, -#endif - {0} -}; - -/* without pwm3-4 */ -static ctl_table w83782d_isa_dir_table_template[] = { - {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp}, - {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vid}, - {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vrm}, - {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan_div}, - {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_alarms}, - {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_beep}, - {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_sens}, - {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_sens}, - {W83781D_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_sens}, - {0} -}; - -/* with pwm3-4 */ -static ctl_table w83782d_i2c_dir_table_template[] = { - {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp}, - {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vid}, - {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vrm}, - {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan_div}, - {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_alarms}, - {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_beep}, - {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_PWM4, "pwm4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_sens}, - {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_sens}, - {W83781D_SYSCTL_SENS3, "sensor3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_sens}, - {0} -}; - -/* w83791D has 10 voltages 5 fans and 3 temps. 2 of the temps are on other - devices. */ -static ctl_table w83791d_dir_table_template[] = { - {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN9, "in9", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN5, "fan5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp}, - {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vid}, - {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan_div}, - {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_alarms}, - {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_beep}, - {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_PWM4, "pwm4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vrm}, - {0} -}; - -static ctl_table w83783s_dir_table_template[] = { - {W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - /* no in1 to maintain compatibility with 781d and 782d. */ - {W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_in}, - {W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan}, - {W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp}, - {W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_temp_add}, - {W83781D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vid}, - {W83781D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_vrm}, - {W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_fan_div}, - {W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_alarms}, - {W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_beep}, - {W83781D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_pwm}, - {W83781D_SYSCTL_SENS1, "sensor1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_sens}, - {W83781D_SYSCTL_SENS2, "sensor2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83781d_sens}, - {0} -}; - - -/* This function is called when: - * w83781d_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and w83781d_driver is still present) */ -static int w83781d_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, w83781d_detect); -} - -static int w83781d_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i, val1 = 0, val2, id; - struct i2c_client *new_client; - struct w83781d_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - int is_isa = i2c_is_isa_adapter(adapter); - enum vendor { winbond, asus } vendid; - - if (!is_isa - && !i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BYTE_DATA)) goto - ERROR0; - - if (is_isa) { - if (!request_region(address, W83781D_EXTENT, "w83781d")) - goto ERROR0; - release_region(address, W83781D_EXTENT); - } - - /* Probe whether there is anything available on this address. Already - done for SMBus clients */ - if (kind < 0) { - if (is_isa) { - -#define REALLY_SLOW_IO - /* We need the timeouts for at least some LM78-like chips. But only - if we read 'undefined' registers. */ - i = inb_p(address + 1); - if (inb_p(address + 2) != i) - goto ERROR0; - if (inb_p(address + 3) != i) - goto ERROR0; - if (inb_p(address + 7) != i) - goto ERROR0; -#undef REALLY_SLOW_IO - - /* Let's just hope nothing breaks here */ - i = inb_p(address + 5) & 0x7f; - outb_p(~i & 0x7f, address + 5); - if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { - outb_p(i, address + 5); - return 0; - } - } - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access w83781d_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct w83781d_data), GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - init_MUTEX(&data->lock); - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &w83781d_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - /* The w8378?d may be stuck in some other bank than bank 0. This may - make reading other information impossible. Specify a force=... or - force_*=... parameter, and the Winbond will be reset to the right - bank. */ - if (kind < 0) { - if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & - 0x80) - goto ERROR1; - - val1 = w83781d_read_value(new_client, W83781D_REG_BANK); - val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); - /* Check for Winbond or Asus ID if in bank 0 */ - if ((!(val1 & 0x07)) && - (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3)) - || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) - goto ERROR1; - - /* If Winbond SMBus, check address at 0x48. - Asus doesn't support, except for the as99127f rev.2 */ - if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) || - ((val1 & 0x80) && (val2 == 0x5c)))) { - if (w83781d_read_value - (new_client, W83781D_REG_I2C_ADDR) != address) - goto ERROR1; - } - } - - /* We have either had a force parameter, or we have already detected the - Winbond. Put it now into bank 0 and Vendor ID High Byte */ - w83781d_write_value(new_client, W83781D_REG_BANK, - (w83781d_read_value(new_client, - W83781D_REG_BANK) & 0x78) | - 0x80); - - /* Determine the chip type. */ - if (kind <= 0) { - /* get vendor ID */ - val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); - if (val2 == 0x5c) - vendid = winbond; - else if (val2 == 0x12) - vendid = asus; - else - goto ERROR1; - - val1 = - w83781d_read_value(new_client, W83781D_REG_WCHIPID); - if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond) - kind = w83781d; - else if (val1 == 0x30 && vendid == winbond) - kind = w83782d; - else if (val1 == 0x40 && vendid == winbond && !is_isa && address == 0x2d) - kind = w83783s; - else if (val1 == 0x21 && vendid == winbond) - kind = w83627hf; - else if (val1 == 0x71 && vendid == winbond && address >= 0x2c) - kind = w83791d; - else if (val1 == 0x31 && !is_isa && address >= 0x28) - kind = as99127f; - else { - if (kind == 0) - printk(KERN_WARNING "w83781d.o: Ignoring " - "'force' parameter for unknown chip " - "at adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - goto ERROR1; - } - } - - if (kind == w83781d) { - type_name = "w83781d"; - client_name = "W83781D chip"; - } else if (kind == w83782d) { - type_name = "w83782d"; - client_name = "W83782D chip"; - } else if (kind == w83783s) { - type_name = "w83783s"; - client_name = "W83783S chip"; - } else if (kind == w83627hf) { - type_name = "w83627hf"; - client_name = "W83627HF chip"; - } else if (kind == as99127f) { - type_name = "as99127f"; - client_name = "AS99127F chip"; - } else if (kind == w83791d) { - type_name = "w83791d"; - client_name = "W83791D chip"; - } else { -#ifdef DEBUG - printk(KERN_ERR "w83781d.o: Internal error: unknown kind (%d)?!?", - kind); -#endif - err = -ENODEV; - goto ERROR1; - } - - /* Reserve the ISA region */ - if (is_isa) - request_region(address, W83781D_EXTENT, type_name); - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* attach secondary i2c lm75-like clients */ - if (!is_isa) { - if (!(data->lm75 = kmalloc(2 * sizeof(struct i2c_client), - GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR4; - } - id = i2c_adapter_id(adapter); - if(force_subclients[0] == id && force_subclients[1] == address) { - for(i = 2; i <= 3; i++) { - if(force_subclients[i] < 0x48 || - force_subclients[i] > 0x4f) { - printk(KERN_ERR "w83781d.o: Invalid subclient address %d; must be 0x48-0x4f\n", - force_subclients[i]); - goto ERROR5; - } - } - w83781d_write_value(new_client, - W83781D_REG_I2C_SUBADDR, - (force_subclients[2] & 0x07) | - ((force_subclients[3] & 0x07) <<4)); - data->lm75[0].addr = force_subclients[2]; - } else { - val1 = w83781d_read_value(new_client, - W83781D_REG_I2C_SUBADDR); - data->lm75[0].addr = 0x48 + (val1 & 0x07); - } - if (kind != w83783s) { - if(force_subclients[0] == id && - force_subclients[1] == address) { - data->lm75[1].addr = force_subclients[3]; - } else { - data->lm75[1].addr = 0x48 + ((val1 >> 4) & 0x07); - } - if(data->lm75[0].addr == data->lm75[1].addr) { - printk(KERN_ERR "w83781d.o: Duplicate addresses 0x%x for subclients.\n", - data->lm75[0].addr); - goto ERROR5; - } - } - if (kind == w83781d) - client_name = "W83781D subclient"; - else if (kind == w83782d) - client_name = "W83782D subclient"; - else if (kind == w83783s) - client_name = "W83783S subclient"; - else if (kind == w83627hf) - client_name = "W83627HF subclient"; - else if (kind == as99127f) - client_name = "AS99127F subclient"; - else if (kind == w83791d) - client_name = "W83791D subclient"; - - - for (i = 0; i <= 1; i++) { - data->lm75[i].data = NULL; /* store all data in w83781d */ - data->lm75[i].adapter = adapter; - data->lm75[i].driver = &w83781d_driver; - data->lm75[i].flags = 0; - strcpy(data->lm75[i].name, client_name); - if ((err = i2c_attach_client(&(data->lm75[i])))) { - printk(KERN_ERR "w83781d.o: Subclient %d registration at address 0x%x failed.\n", - i, data->lm75[i].addr); - if (i == 1) - goto ERROR6; - goto ERROR5; - } - if (kind == w83783s) - break; - } - } else { - data->lm75 = NULL; - } - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, - type_name, - (kind == as99127f) ? - as99127f_dir_table_template : - (kind == w83781d) ? - w83781d_dir_table_template : - (kind == w83783s) ? - w83783s_dir_table_template : - (kind == w83791d ) ? - w83791d_dir_table_template : - (is_isa || kind == w83627hf) ? - w83782d_isa_dir_table_template : - w83782d_i2c_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto ERROR7; - } - data->sysctl_id = i; - - /* Only PWM2 can be disabled */ - for(i = 0; i < 4; i++) - data->pwmenable[i] = 1; - - /* Initialize the chip */ - w83781d_init_client(new_client); - return 0; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR7: - if (!is_isa) - i2c_detach_client(& - (((struct - w83781d_data *) (new_client->data))-> - lm75[1])); - ERROR6: - if (!is_isa) - i2c_detach_client(& - (((struct - w83781d_data *) (new_client->data))-> - lm75[0])); - ERROR5: - if (!is_isa) - kfree(((struct w83781d_data *) (new_client->data))->lm75); - ERROR4: - i2c_detach_client(new_client); - ERROR3: - if (is_isa) - release_region(address, W83781D_EXTENT); - ERROR1: - kfree(data); - ERROR0: - return err; -} - -static int w83781d_detach_client(struct i2c_client *client) -{ - int err; - struct w83781d_data *data = client->data; - - i2c_deregister_entry(data->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - (KERN_ERR "w83781d.o: Client deregistration failed, client not detached.\n"); - return err; - } - - if(i2c_is_isa_client(client)) { - release_region(client->addr, W83781D_EXTENT); - } else { - i2c_detach_client(&(data->lm75[0])); - if (data->type != w83783s) - i2c_detach_client(&(data->lm75[1])); - kfree(data->lm75); - } - kfree(data); - - return 0; -} - -/* The SMBus locks itself, usually, but nothing may access the Winbond between - bank switches. ISA access must always be locked explicitly! - We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, - would slow down the W83781D access and should not be necessary. - There are some ugly typecasts here, but the good news is - they should - nowhere else be necessary! */ -static int w83781d_read_value(struct i2c_client *client, u16 reg) -{ - int res, word_sized, bank; - struct i2c_client *cl; - - down(&(((struct w83781d_data *) (client->data))->lock)); - if (i2c_is_isa_client(client)) { - word_sized = (((reg & 0xff00) == 0x100) - || ((reg & 0xff00) == 0x200)) - && (((reg & 0x00ff) == 0x50) - || ((reg & 0x00ff) == 0x53) - || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - } - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); - res = inb_p(client->addr + W83781D_DATA_REG_OFFSET); - if (word_sized) { - outb_p((reg & 0xff) + 1, - client->addr + W83781D_ADDR_REG_OFFSET); - res = - (res << 8) + inb_p(client->addr + - W83781D_DATA_REG_OFFSET); - } - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); - } - } else { - bank = (reg >> 8) & 0x0f; - if (bank > 2) - /* switch banks */ - i2c_smbus_write_byte_data(client, W83781D_REG_BANK, - bank); - if (bank == 0 || bank > 2) { - res = i2c_smbus_read_byte_data(client, reg & 0xff); - } else { - /* switch to subclient */ - cl = - &(((struct w83781d_data *) (client->data))-> - lm75[bank - 1]); - /* convert from ISA to LM75 I2C addresses */ - switch (reg & 0xff) { - case 0x50: /* TEMP */ - res = swab16(i2c_smbus_read_word_data(cl, 0)); - break; - case 0x52: /* CONFIG */ - res = i2c_smbus_read_byte_data(cl, 1); - break; - case 0x53: /* HYST */ - res = swab16(i2c_smbus_read_word_data(cl, 2)); - break; - case 0x55: /* OVER */ - default: - res = swab16(i2c_smbus_read_word_data(cl, 3)); - break; - } - } - if (bank > 2) - i2c_smbus_write_byte_data(client, W83781D_REG_BANK, - 0); - } - up(&(((struct w83781d_data *) (client->data))->lock)); - return res; -} - -static int w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) -{ - int word_sized, bank; - struct i2c_client *cl; - - down(&(((struct w83781d_data *) (client->data))->lock)); - if (i2c_is_isa_client(client)) { - word_sized = (((reg & 0xff00) == 0x100) - || ((reg & 0xff00) == 0x200)) - && (((reg & 0x00ff) == 0x53) - || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - } - outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); - if (word_sized) { - outb_p(value >> 8, - client->addr + W83781D_DATA_REG_OFFSET); - outb_p((reg & 0xff) + 1, - client->addr + W83781D_ADDR_REG_OFFSET); - } - outb_p(value & 0xff, - client->addr + W83781D_DATA_REG_OFFSET); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - client->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); - } - } else { - bank = (reg >> 8) & 0x0f; - if (bank > 2) - /* switch banks */ - i2c_smbus_write_byte_data(client, W83781D_REG_BANK, - bank); - if (bank == 0 || bank > 2) { - i2c_smbus_write_byte_data(client, reg & 0xff, - value & 0xff); - } else { - /* switch to subclient */ - cl = &(((struct w83781d_data *) (client->data))-> - lm75[bank - 1]); - /* convert from ISA to LM75 I2C addresses */ - switch (reg & 0xff) { - case 0x52: /* CONFIG */ - i2c_smbus_write_byte_data(cl, 1, value & 0xff); - break; - case 0x53: /* HYST */ - i2c_smbus_write_word_data(cl, 2, swab16(value)); - break; - case 0x55: /* OVER */ - i2c_smbus_write_word_data(cl, 3, swab16(value)); - break; - } - } - if (bank > 2) - i2c_smbus_write_byte_data(client, W83781D_REG_BANK, - 0); - } - up(&(((struct w83781d_data *) (client->data))->lock)); - return 0; -} - -/* Called when we have found a new W83781D. */ -static void w83781d_init_client(struct i2c_client *client) -{ - struct w83781d_data *data = client->data; - int i, p; - int type = data->type; - u8 tmp; - - if(init && type != as99127f) { /* this resets registers we don't have - documentation for on the as99127f */ - /* save these registers */ - i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); - p = w83781d_read_value(client, W83781D_REG_PWMCLK12); - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others */ - w83781d_write_value(client, W83781D_REG_CONFIG, 0x80); - /* Restore the registers and disable power-on abnormal beep. - This saves FAN 1/2/3 input/output values set by BIOS. */ - w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80); - w83781d_write_value(client, W83781D_REG_PWMCLK12, p); - /* Disable master beep-enable (reset turns it on). - Individual beeps should be reset to off but for some reason - disabling this bit helps some people not get beeped */ - w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0); - } - - data->vrm = (type == w83791d) ? 90 : 82; - - if ((type != w83781d) && (type != as99127f)) { - tmp = w83781d_read_value(client, W83781D_REG_SCFG1); - for (i = 1; i <= 3; i++) { - if (!(tmp & BIT_SCFG1[i - 1])) { - data->sens[i - 1] = W83781D_DEFAULT_BETA; - } else { - if (w83781d_read_value - (client, - W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) - data->sens[i - 1] = 1; - else - data->sens[i - 1] = 2; - } - if (type == w83783s && i == 2) - break; - } - } -#ifdef W83781D_RT -/* - Fill up the RT Tables. - We assume that they are 32 bytes long, in order for temp 1-3. - Data sheet documentation is sparse. - We also assume that it is only for the 781D although I suspect - that the others support it as well.... -*/ - - if (init && type == w83781d) { - u16 k = 0; -/* - Auto-indexing doesn't seem to work... - w83781d_write_value(client,W83781D_REG_RT_IDX,0); -*/ - for (i = 0; i < 3; i++) { - int j; - for (j = 0; j < 32; j++) { - w83781d_write_value(client, - W83781D_REG_RT_IDX, - k++); - data->rt[i][j] = - w83781d_read_value(client, - W83781D_REG_RT_VAL); - } - } - } -#endif /* W83781D_RT */ - - if (init && type != as99127f) { - w83781d_write_value(client, W83781D_REG_TEMP2_CONFIG, 0x00); - if (type != w83783s) { - w83781d_write_value(client, W83781D_REG_TEMP3_CONFIG, - 0x00); - } - } - - /* Start monitoring */ - w83781d_write_value(client, W83781D_REG_CONFIG, - (w83781d_read_value(client, - W83781D_REG_CONFIG) & 0xf7) - | 0x01); -} - -static void w83781d_update_client(struct i2c_client *client) -{ - struct w83781d_data *data = client->data; - int i; - - down(&data->update_lock); - - if (time_after(jiffies - data->last_updated, HZ + HZ / 2) || - time_before(jiffies, data->last_updated) || !data->valid) { - pr_debug(KERN_DEBUG "Starting device update\n"); - - for (i = 0; i <= 9; i++) { - if ((data->type == w83783s) - && (i == 1)) - continue; /* 783S has no in1 */ - if (data->type == w83791d) { - data->in[i] = - w83781d_read_value(client, W83791D_REG_IN(i)); - data->in_min[i] = - w83781d_read_value(client, - W83791D_REG_IN_MIN(i)); - data->in_max[i] = - w83781d_read_value(client, - W83791D_REG_IN_MAX(i)); - } else { - data->in[i] = - w83781d_read_value(client, W83781D_REG_IN(i)); - data->in_min[i] = - w83781d_read_value(client, - W83781D_REG_IN_MIN(i)); - data->in_max[i] = - w83781d_read_value(client, - W83781D_REG_IN_MAX(i)); - } - if ((data->type != w83782d) - && (data->type != w83627hf) && (i == 6) - && (data->type != w83791d)) - break; - - if (data->type != w83791d && i == 8) - break; - } - for (i = 1; i <= 5; i++) { - data->fan[i - 1] = - w83781d_read_value(client, W83781D_REG_FAN(i)); - data->fan_min[i - 1] = - w83781d_read_value(client, - W83781D_REG_FAN_MIN(i)); - if (data->type != w83791d && i == 3) break; - } - if (data->type != w83781d && data->type != as99127f) { - for (i = 1; i <= 4; i++) { - data->pwm[i - 1] = - w83781d_read_value(client, - W83781D_REG_PWM(data->type, i)); - if (((data->type == w83783s) - || (data->type == w83627hf) - || ((data->type == w83782d) - && i2c_is_isa_client(client))) - && i == 2) - break; - } - /* Only PWM2 can be disabled */ - data->pwmenable[1] = (w83781d_read_value(client, - W83781D_REG_PWMCLK12) & 0x08) >> 3; - } - - data->temp = w83781d_read_value(client, W83781D_REG_TEMP); - data->temp_over = - w83781d_read_value(client, W83781D_REG_TEMP_OVER); - data->temp_hyst = - w83781d_read_value(client, W83781D_REG_TEMP_HYST); - data->temp_add[0] = - w83781d_read_value(client, W83781D_REG_TEMP2); - data->temp_add_over[0] = - w83781d_read_value(client, W83781D_REG_TEMP2_OVER); - data->temp_add_hyst[0] = - w83781d_read_value(client, W83781D_REG_TEMP2_HYST); - if (data->type != w83783s) { - data->temp_add[1] = - w83781d_read_value(client, W83781D_REG_TEMP3); - data->temp_add_over[1] = - w83781d_read_value(client, W83781D_REG_TEMP3_OVER); - data->temp_add_hyst[1] = - w83781d_read_value(client, W83781D_REG_TEMP3_HYST); - } - i = w83781d_read_value(client, W83781D_REG_VID_FANDIV); - data->vid = i & 0x0f; - data->vid |= (w83781d_read_value(client, - W83781D_REG_CHIPID) & 0x01) << 4; - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - data->fan_div[2] = (w83781d_read_value(client, - W83781D_REG_PIN) >> 6) & 0x03; - if ((data->type != w83781d) && (data->type != as99127f)) { - i = w83781d_read_value(client, W83781D_REG_VBAT); - data->fan_div[0] |= (i >> 3) & 0x04; - data->fan_div[1] |= (i >> 4) & 0x04; - data->fan_div[2] |= (i >> 5) & 0x04; - } - - if ((data->type == w83782d) || (data->type == w83627hf)) { - data->alarms = w83781d_read_value(client, - W83782D_REG_ALARM1) - | (w83781d_read_value(client, - W83782D_REG_ALARM2) << 8) - | (w83781d_read_value(client, - W83782D_REG_ALARM3) << 16); - } else if (data->type == w83783s) { - /* Only two real-time status registers */ - data->alarms = w83781d_read_value(client, - W83782D_REG_ALARM1) - | (w83781d_read_value(client, - W83782D_REG_ALARM2) << 8); - } else if (data->type == w83791d) { - data->alarms = w83781d_read_value(client, - W83791D_REG_ALARM1) - | (w83781d_read_value(client, - W83791D_REG_ALARM2) << 8) - | (w83781d_read_value(client, - W83791D_REG_ALARM3) << 16); - } else { - /* No real-time status registers, fall back to - interrupt status registers */ - data->alarms = w83781d_read_value(client, - W83781D_REG_ALARM1) - | (w83781d_read_value(client, - W83781D_REG_ALARM2) << 8); - } - - i = w83781d_read_value(client, W83781D_REG_BEEP_INTS2); - data->beep_enable = i >> 7; - data->beeps = ((i & 0x7f) << 8) + - w83781d_read_value(client, W83781D_REG_BEEP_INTS1); - if ((data->type != w83781d) && (data->type != as99127f) - && (data->type != w83791d)) { - data->beeps |= - w83781d_read_value(client, - W83781D_REG_BEEP_INTS3) << 16; - } - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ -static void w83781d_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int nr = ctl_name - W83781D_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0]); - w83781d_write_value(client, W83781D_REG_IN_MIN(nr), - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1]); - w83781d_write_value(client, W83781D_REG_IN_MAX(nr), - data->in_max[nr]); - } - } -} - -void w83781d_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int nr = ctl_name - W83781D_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - results[1] = FAN_FROM_REG(data->fan[nr - 1], - DIV_FROM_REG(data->fan_div[nr - 1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr - 1] = - FAN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr-1])); - w83781d_write_value(client, - W83781D_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); - } - } -} - -void w83781d_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over = TEMP_TO_REG(results[0]); - w83781d_write_value(client, W83781D_REG_TEMP_OVER, - data->temp_over); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - w83781d_write_value(client, W83781D_REG_TEMP_HYST, - data->temp_hyst); - } - } -} - -void w83781d_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int nr = ctl_name - W83781D_SYSCTL_TEMP2; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = LM75_TEMP_FROM_REG(data->temp_add_over[nr]); - results[1] = LM75_TEMP_FROM_REG(data->temp_add_hyst[nr]); - results[2] = LM75_TEMP_FROM_REG(data->temp_add[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_add_over[nr] = - LM75_TEMP_TO_REG(results[0]); - w83781d_write_value(client, - nr ? W83781D_REG_TEMP3_OVER : - W83781D_REG_TEMP2_OVER, - data->temp_add_over[nr]); - } - if (*nrels_mag >= 2) { - data->temp_add_hyst[nr] = - LM75_TEMP_TO_REG(results[1]); - w83781d_write_value(client, - nr ? W83781D_REG_TEMP3_HYST : - W83781D_REG_TEMP2_HYST, - data->temp_add_hyst[nr]); - } - } -} - - -void w83781d_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = vid_from_reg(data->vid, data->vrm); - *nrels_mag = 1; - } -} - -void w83781d_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) - data->vrm = results[0]; - } -} - -void w83781d_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void w83781d_beep(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int val; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = BEEP_ENABLE_FROM_REG(data->beep_enable); - results[1] = BEEPS_FROM_REG(data->beeps, data->type); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 2) { - data->beeps = BEEPS_TO_REG(results[1], data->type); - w83781d_write_value(client, W83781D_REG_BEEP_INTS1, - data->beeps & 0xff); - if ((data->type != w83781d) && - (data->type != as99127f)) { - w83781d_write_value(client, - W83781D_REG_BEEP_INTS3, - ((data-> beeps) >> 16) & - 0xff); - } - val = (data->beeps >> 8) & 0x7f; - } else if (*nrels_mag >= 1) - val = - w83781d_read_value(client, - W83781D_REG_BEEP_INTS2) & - 0x7f; - if (*nrels_mag >= 1) { - data->beep_enable = BEEP_ENABLE_TO_REG(results[0]); - w83781d_write_value(client, W83781D_REG_BEEP_INTS2, - val | data->beep_enable << 7); - } - } -} - -void w83781d_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int old, old2, old3 = 0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - results[2] = DIV_FROM_REG(data->fan_div[2]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = w83781d_read_value(client, W83781D_REG_VID_FANDIV); - /* w83781d and as99127f don't have extended divisor bits */ - if ((data->type != w83781d) && data->type != as99127f) { - old3 = - w83781d_read_value(client, W83781D_REG_VBAT); - } - if (*nrels_mag >= 3) { - data->fan_div[2] = - DIV_TO_REG(results[2], data->type); - old2 = w83781d_read_value(client, W83781D_REG_PIN); - old2 = - (old2 & 0x3f) | ((data->fan_div[2] & 0x03) << 6); - w83781d_write_value(client, W83781D_REG_PIN, old2); - if ((data->type != w83781d) && - (data->type != as99127f)) { - old3 = - (old3 & 0x7f) | - ((data->fan_div[2] & 0x04) << 5); - } - } - if (*nrels_mag >= 2) { - data->fan_div[1] = - DIV_TO_REG(results[1], data->type); - old = - (old & 0x3f) | ((data->fan_div[1] & 0x03) << 6); - if ((data->type != w83781d) && - (data->type != as99127f)) { - old3 = - (old3 & 0xbf) | - ((data->fan_div[1] & 0x04) << 4); - } - } - if (*nrels_mag >= 1) { - data->fan_div[0] = - DIV_TO_REG(results[0], data->type); - old = - (old & 0xcf) | ((data->fan_div[0] & 0x03) << 4); - w83781d_write_value(client, W83781D_REG_VID_FANDIV, - old); - if ((data->type != w83781d) && - (data->type != as99127f)) { - old3 = - (old3 & 0xdf) | - ((data->fan_div[0] & 0x04) << 3); - w83781d_write_value(client, - W83781D_REG_VBAT, - old3); - } - } - } -} - -void w83781d_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int nr = 1 + ctl_name - W83781D_SYSCTL_PWM1; - int j, k; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = PWM_FROM_REG(data->pwm[nr - 1]); - results[1] = data->pwmenable[nr - 1]; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->pwm[nr - 1] = PWM_TO_REG(results[0]); - w83781d_write_value(client, - W83781D_REG_PWM(data->type, nr), - data->pwm[nr - 1]); - } - /* only PWM2 can be enabled/disabled */ - if (*nrels_mag >= 2 && nr == 2) { - j = w83781d_read_value(client, W83781D_REG_PWMCLK12); - k = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); - if(results[1]) { - if(!(j & 0x08)) - w83781d_write_value(client, - W83781D_REG_PWMCLK12, j | 0x08); - if(k & 0x10) - w83781d_write_value(client, - W83781D_REG_BEEP_CONFIG, k & 0xef); - data->pwmenable[1] = 1; - } else { - if(j & 0x08) - w83781d_write_value(client, - W83781D_REG_PWMCLK12, j & 0xf7); - if(!(k & 0x10)) - w83781d_write_value(client, - W83781D_REG_BEEP_CONFIG, j | 0x10); - data->pwmenable[1] = 0; - } - } - } -} - -void w83781d_sens(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int nr = 1 + ctl_name - W83781D_SYSCTL_SENS1; - u8 tmp; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->sens[nr - 1]; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - switch (results[0]) { - case 1: /* PII/Celeron diode */ - tmp = w83781d_read_value(client, - W83781D_REG_SCFG1); - w83781d_write_value(client, - W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - - 1]); - tmp = w83781d_read_value(client, - W83781D_REG_SCFG2); - w83781d_write_value(client, - W83781D_REG_SCFG2, - tmp | BIT_SCFG2[nr - - 1]); - data->sens[nr - 1] = results[0]; - break; - case 2: /* 3904 */ - tmp = w83781d_read_value(client, - W83781D_REG_SCFG1); - w83781d_write_value(client, - W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - - 1]); - tmp = w83781d_read_value(client, - W83781D_REG_SCFG2); - w83781d_write_value(client, - W83781D_REG_SCFG2, - tmp & ~BIT_SCFG2[nr - - 1]); - data->sens[nr - 1] = results[0]; - break; - case W83781D_DEFAULT_BETA: /* thermistor */ - tmp = w83781d_read_value(client, - W83781D_REG_SCFG1); - w83781d_write_value(client, - W83781D_REG_SCFG1, - tmp & ~BIT_SCFG1[nr - - 1]); - data->sens[nr - 1] = results[0]; - break; - default: - printk - (KERN_ERR "w83781d.o: Invalid sensor type %ld; must be 1, 2, or %d\n", - results[0], W83781D_DEFAULT_BETA); - break; - } - } - } -} - -#ifdef W83781D_RT -static void w83781d_rt(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int nr = 1 + ctl_name - W83781D_SYSCTL_RT1; - int i; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - for (i = 0; i < 32; i++) { - results[i] = data->rt[nr - 1][i]; - } - *nrels_mag = 32; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag > 32) - *nrels_mag = 32; - for (i = 0; i < *nrels_mag; i++) { - /* fixme: no bounds checking 0-255 */ - data->rt[nr - 1][i] = results[i]; - w83781d_write_value(client, W83781D_REG_RT_IDX, i); - w83781d_write_value(client, W83781D_REG_RT_VAL, - data->rt[nr - 1][i]); - } - } -} -#endif - -static int __init sm_w83781d_init(void) -{ - printk(KERN_INFO "w83781d.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&w83781d_driver); -} - -static void __exit sm_w83781d_exit(void) -{ - i2c_del_driver(&w83781d_driver); -} - - - -MODULE_AUTHOR("Frodo Looijaard , " - "Philip Edelbrock , " - "and Mark Studebaker "); -MODULE_DESCRIPTION("W83781D driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_w83781d_init); -module_exit(sm_w83781d_exit); diff --git a/kernel/chips/w83792d.c b/kernel/chips/w83792d.c deleted file mode 100644 index aa08572f..00000000 --- a/kernel/chips/w83792d.c +++ /dev/null @@ -1,1532 +0,0 @@ -/* - w83792d.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2004, 2005 Winbond Electronics Corp. - Chunhao Huang - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Note: - 1. This driver is only for 2.4 kernel(2.4.10 or later), 2.6 kernel - need a different driver. - 2. This driver is only for Winbond W83792D C version device, there - are also some motherboards with B version W83792D device. The - calculation method to in6-in7(measured value, limits) is a little - different between C and B version. C or B version can be identified - by CR[0x49h]. - 3. The function of chassis open detection need further test. - 4. The function of vid and vrm has not been finished, because I'm NOT - very familiar with them. If someone can finish it, that's good, - then please delete this note 4. -*/ - -/* - Supports following chips: - - Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA - w83792d 9 7 3 3 0x7a 0x5ca3 yes no -*/ - -#include -#include -#include -#include -#include -#include "version.h" -#include "sensors_vid.h" - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x2c, 0x2f, SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(w83792d); -SENSORS_MODULE_PARM(force_subclients, "List of subclient addresses: " \ - "{bus, clientaddr, subclientaddr1, subclientaddr2}"); - -static int init; -MODULE_PARM(init, "i"); -MODULE_PARM_DESC(init, "Set to one for chip initialization"); - -/* Enable/Disable w83792d debugging output */ -/* #define W83792D_DEBUG 1 */ - -/* Constants specified below */ -#define W83792D_REG_GPIO_EN 0x1A -#define W83792D_REG_CONFIG 0x40 -#define W83792D_REG_I2C_ADDR 0x48 -#define W83792D_REG_CHIPID 0x49 /* contains version ID: A/B/C */ -#define W83792D_REG_I2C_SUBADDR 0x4A -#define W83792D_REG_PIN 0x4B -#define W83792D_REG_IRQ 0x4C -#define W83792D_REG_BANK 0x4E -#define W83792D_REG_CHIPMAN 0x4F /* contains the vendor ID */ -#define W83792D_REG_WCHIPID 0x58 /* contains the chip ID */ -#define W83792D_REG_VID_IN_B 0x17 /* ctroll in0/in1 's limit modifiability */ - -static const u8 W83792D_REG_IN[9] = { - 0x20, /* Vcore A in DataSheet */ - 0x21, /* Vcore B in DataSheet */ - 0x22, /* VIN0 in DataSheet */ - 0x23, /* VIN1 in DataSheet */ - 0x24, /* VIN2 in DataSheet */ - 0x25, /* VIN3 in DataSheet */ - 0x26, /* 5VCC in DataSheet */ - 0xB0, /* 5VSB in DataSheet */ - 0xB1 /* VBAT in DataSheet */ -}; -#define W83792D_REG_LOW_BITS1 0x3E /* Low Bits I in DataSheet */ -#define W83792D_REG_LOW_BITS2 0x3F /* Low Bits II in DataSheet */ -static const u8 W83792D_REG_IN_MAX[9] = { - 0x2B, /* Vcore A High Limit in DataSheet */ - 0x2D, /* Vcore B High Limit in DataSheet */ - 0x2F, /* VIN0 High Limit in DataSheet */ - 0x31, /* VIN1 High Limit in DataSheet */ - 0x33, /* VIN2 High Limit in DataSheet */ - 0x35, /* VIN3 High Limit in DataSheet */ - 0x37, /* 5VCC High Limit in DataSheet */ - 0xB4, /* 5VSB High Limit in DataSheet */ - 0xB6 /* VBAT High Limit in DataSheet */ -}; -static const u8 W83792D_REG_IN_MIN[9] = { - 0x2C, /* Vcore A Low Limit in DataSheet */ - 0x2E, /* Vcore B Low Limit in DataSheet */ - 0x30, /* VIN0 Low Limit in DataSheet */ - 0x32, /* VIN1 Low Limit in DataSheet */ - 0x34, /* VIN2 Low Limit in DataSheet */ - 0x36, /* VIN3 Low Limit in DataSheet */ - 0x38, /* 5VCC Low Limit in DataSheet */ - 0xB5, /* 5VSB Low Limit in DataSheet */ - 0xB7 /* VBAT Low Limit in DataSheet */ -}; - -static const u8 W83792D_REG_FAN[7] = { - 0x28, /* FAN 1 Count in DataSheet */ - 0x29, /* FAN 2 Count in DataSheet */ - 0x2A, /* FAN 3 Count in DataSheet */ - 0xB8, /* FAN 4 Count in DataSheet */ - 0xB9, /* FAN 5 Count in DataSheet */ - 0xBA, /* FAN 6 Count in DataSheet */ - 0xBE /* FAN 7 Count in DataSheet */ -}; -static const u8 W83792D_REG_FAN_MIN[7] = { - 0x3B, /* FAN 1 Count Low Limit in DataSheet */ - 0x3C, /* FAN 2 Count Low Limit in DataSheet */ - 0x3D, /* FAN 3 Count Low Limit in DataSheet */ - 0xBB, /* FAN 4 Count Low Limit in DataSheet */ - 0xBC, /* FAN 5 Count Low Limit in DataSheet */ - 0xBD, /* FAN 6 Count Low Limit in DataSheet */ - 0xBF /* FAN 7 Count Low Limit in DataSheet */ -}; -#define W83792D_REG_FAN_CFG 0x84 /* FAN Configuration in DataSheet */ -static const u8 W83792D_REG_PWM[7] = { - 0x81, /* FAN 1 Duty Cycle, be used to control */ - 0x83, /* FAN 2 Duty Cycle, be used to control */ - 0x94, /* FAN 3 Duty Cycle, be used to control */ - 0xA3, /* FAN 4 Duty Cycle, be used to control */ - 0xA4, /* FAN 5 Duty Cycle, be used to control */ - 0xA5, /* FAN 6 Duty Cycle, be used to control */ - 0xA6 /* FAN 7 Duty Cycle, be used to control */ -}; - -#define W83792D_REG_TEMP1 0x27 /* TEMP 1 in DataSheet */ -#define W83792D_REG_TEMP1_OVER 0x39 /* TEMP 1 High Limit in DataSheet */ -#define W83792D_REG_TEMP1_HYST 0x3A /* TEMP 1 Low Limit in DataSheet */ -static const u8 W83792D_REG_TEMP_ADD[2][7] = { - { 0xC0, /* TEMP 2 in DataSheet */ - 0xC1, /* TEMP 2(0.5 deg) in DataSheet */ - 0xC5, /* TEMP 2 Over High part in DataSheet */ - 0xC6, /* TEMP 2 Over Low part in DataSheet */ - 0xC3, /* TEMP 2 Thyst High part in DataSheet */ - 0xC4, /* TEMP 2 Thyst Low part in DataSheet */ - 0xC2 }, /* TEMP 2 Config in DataSheet */ - { 0xC8, /* TEMP 3 in DataSheet */ - 0xC9, /* TEMP 3(0.5 deg) in DataSheet */ - 0xCD, /* TEMP 3 Over High part in DataSheet */ - 0xCE, /* TEMP 3 Over Low part in DataSheet */ - 0xCB, /* TEMP 3 Thyst High part in DataSheet */ - 0xCC, /* TEMP 3 Thyst Low part in DataSheet */ - 0xCA } /* TEMP 3 Config in DataSheet */ -}; - -static const u8 W83792D_REG_FAN_DIV[4] = { - 0x47, /* contains FAN2 and FAN1 Divisor */ - 0x5B, /* contains FAN4 and FAN3 Divisor */ - 0x5C, /* contains FAN6 and FAN5 Divisor */ - 0x9E /* contains FAN7 Divisor. */ -}; - -#define W83792D_REG_ALARM1 0xA9 /* realtime status register1 */ -#define W83792D_REG_ALARM2 0xAA /* realtime status register2 */ -#define W83792D_REG_ALARM3 0xAB /* realtime status register3 */ -#define W83792D_REG_CASE_OPEN 0x42 /* Bit 5: Case Open status bit */ -#define W83792D_REG_CASE_OPEN_CLR 0x44 /* Bit 7: Case Open CLR_CHS/Reset bit */ - -static const u8 W83792D_REG_THERMAL[3] = { - 0x85, /* SmartFanI: Fan1 target value */ - 0x86, /* SmartFanI: Fan2 target value */ - 0x96 /* SmartFanI: Fan3 target value */ -}; - -static const u8 W83792D_REG_FAN_TOL[3] = { - 0x87, /* (bit3-0)SmartFan Fan1 tolerance */ - 0x87, /* (bit7-4)SmartFan Fan2 tolerance */ - 0x97 /* (bit3-0)SmartFan Fan3 tolerance */ -}; - -static const u8 W83792D_REG_POINTS[3][4] = { - { 0x85, /* SmartFanII: Fan1 temp point 1 */ - 0xE3, /* SmartFanII: Fan1 temp point 2 */ - 0xE4, /* SmartFanII: Fan1 temp point 3 */ - 0xE5 }, /* SmartFanII: Fan1 temp point 4 */ - { 0x86, /* SmartFanII: Fan2 temp point 1 */ - 0xE6, /* SmartFanII: Fan2 temp point 2 */ - 0xE7, /* SmartFanII: Fan2 temp point 3 */ - 0xE8 }, /* SmartFanII: Fan2 temp point 4 */ - { 0x96, /* SmartFanII: Fan3 temp point 1 */ - 0xE9, /* SmartFanII: Fan3 temp point 2 */ - 0xEA, /* SmartFanII: Fan3 temp point 3 */ - 0xEB } /* SmartFanII: Fan3 temp point 4 */ -}; - -static const u8 W83792D_REG_LEVELS[3][4] = { - { 0x88, /* (bit3-0) SmartFanII: Fan1 Non-Stop */ - 0x88, /* (bit7-4) SmartFanII: Fan1 Level 1 */ - 0xE0, /* (bit7-4) SmartFanII: Fan1 Level 2 */ - 0xE0 }, /* (bit3-0) SmartFanII: Fan1 Level 3 */ - { 0x89, /* (bit3-0) SmartFanII: Fan2 Non-Stop */ - 0x89, /* (bit7-4) SmartFanII: Fan2 Level 1 */ - 0xE1, /* (bit7-4) SmartFanII: Fan2 Level 2 */ - 0xE1 }, /* (bit3-0) SmartFanII: Fan2 Level 3 */ - { 0x98, /* (bit3-0) SmartFanII: Fan3 Non-Stop */ - 0x98, /* (bit7-4) SmartFanII: Fan3 Level 1 */ - 0xE2, /* (bit7-4) SmartFanII: Fan3 Level 2 */ - 0xE2 } /* (bit3-0) SmartFanII: Fan3 Level 3 */ -}; - -static inline u8 FAN_TO_REG(long rpm, int div) -{ - if (rpm == 0) - return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT(1350000/(rpm * div), 1, 254); -} - -#define IN_FROM_REG(nr,val) (((nr)<=1)?(val*2): \ - ((((nr)==6)||((nr)==7))?(val*6):(val*4))) -#define IN_TO_REG(nr,val) (((nr)<=1)?(val/2): \ - ((((nr)==6)||((nr)==7))?(val/6):(val/4))) -#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10) -#define TEMP_TO_REG(val) (SENSORS_LIMIT((val>=0)?((val)/10):((val)/10+256), 0, 255)) -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) -#define DIV_FROM_REG(val) (1 << (val)) - -#ifdef W83792D_DEBUG -#define ENTER() printk(KERN_DEBUG "w83792d: ENTERING %s, line: %d\n", __FUNCTION__, __LINE__); -#define LEAVE() printk(KERN_DEBUG "w83792d: LEAVING %s, line: %d\n", __FUNCTION__, __LINE__); -#else -#define ENTER() -#define LEAVE() -#endif - -struct w83792d_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - struct i2c_client *lm75[2]; /* for secondary I2C addresses */ - - u8 in[9]; /* Register value */ - u8 in_max[9]; /* Register value */ - u8 in_min[9]; /* Register value */ - u16 low_bits; /* Register value */ - u8 has_fan; /* Bit vector */ - u8 fan[7]; /* Register value */ - u8 fan_min[7]; /* Register value */ - u8 fan_cfg; /* Configure Fan Mode */ - u8 temp1[3]; /* Register value */ - u8 temp_add[2][7]; /* Register value */ - u8 fan_div[7]; /* Fan Divisor */ - /*u8 vid; Register encoding, combined */ - u8 pwm[7]; /* We only consider the first 3 set of pwm, - although 792 chip has 7 set of pwm. */ - u8 pwm_flag[7]; /* indicates PWM or DC mode: 1->PWM; 0->DC */ - /* u8 vrm; VRM version */ - u32 alarms; /* realtime status register encoding,combined */ - u8 chassis[2]; /* [0]->Chassis status, [1]->CLR_CHS */ - u8 thermal_cruise[3]; /* Smart FanI: Fan1,2,3 target value */ - u8 fan_tolerance[3]; /* Fan1,2,3 tolerance(Smart Fan I/II) */ - u8 sf2_points[3][4]; /* Smart FanII: Fan1,2,3 temperature points */ - u8 sf2_levels[3][4]; /* Smart FanII: Fan1,2,3 duty cycle levels */ -}; - -/* Read the w83792d register value, only use bank 0 of the 792 chip */ -static inline int -w83792d_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -/* Write value into the w83792d registers, only use bank 0 of the 792 chip */ -static inline int -w83792d_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static int w83792d_attach_adapter(struct i2c_adapter *adapter); -static int w83792d_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int w83792d_detach_client(struct i2c_client *client); - -static void w83792d_init_client(struct i2c_client *client); -static void w83792d_update_client(struct i2c_client *client); -#ifdef W83792D_DEBUG -static void w83792d_print_debug(struct w83792d_data *data); -#endif -static void w83792d_in(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -/*static void w83792d_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_vrm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); */ -static void w83792d_set_fan_div(struct i2c_client *client, - int nr, u8 newdiv); -static void w83792d_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_chassis(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_pwm_flag(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_fan_cfg(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_thermal_cruise(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_fan_tolerance(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_sf2_points(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83792d_sf2_levels(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver w83792d_driver = { - .name = "W83792D sensor driver", - .flags = I2C_DF_NOTIFY, - .attach_adapter = w83792d_attach_adapter, - .detach_client = w83792d_detach_client, -}; - -/* The /proc/sys entries */ -/* -- SENSORS SYSCTL START -- */ - -#define W83792D_SYSCTL_IN0 1000 -#define W83792D_SYSCTL_IN1 1001 -#define W83792D_SYSCTL_IN2 1002 -#define W83792D_SYSCTL_IN3 1003 -#define W83792D_SYSCTL_IN4 1004 -#define W83792D_SYSCTL_IN5 1005 -#define W83792D_SYSCTL_IN6 1006 -#define W83792D_SYSCTL_IN7 1007 -#define W83792D_SYSCTL_IN8 1008 -#define W83792D_SYSCTL_FAN1 1101 -#define W83792D_SYSCTL_FAN2 1102 -#define W83792D_SYSCTL_FAN3 1103 -#define W83792D_SYSCTL_FAN4 1104 -#define W83792D_SYSCTL_FAN5 1105 -#define W83792D_SYSCTL_FAN6 1106 -#define W83792D_SYSCTL_FAN7 1107 - -#define W83792D_SYSCTL_TEMP1 1200 -#define W83792D_SYSCTL_TEMP2 1201 -#define W83792D_SYSCTL_TEMP3 1202 -/*#define W83792D_SYSCTL_VID 1300 -#define W83792D_SYSCTL_VRM 1301*/ -#define W83792D_SYSCTL_PWM_FLAG 1400 -#define W83792D_SYSCTL_PWM1 1401 -#define W83792D_SYSCTL_PWM2 1402 -#define W83792D_SYSCTL_PWM3 1403 -#define W83792D_SYSCTL_FAN_CFG 1500 /* control Fan Mode */ -#define W83792D_SYSCTL_FAN_DIV 1501 -#define W83792D_SYSCTL_CHASSIS 1502 /* control Case Open */ -#define W83792D_SYSCTL_ALARMS 1503 - -#define W83792D_SYSCTL_THERMAL_CRUISE 1600 /* Smart Fan I: target value */ -#define W83792D_SYSCTL_FAN_TOLERANCE 1601 /* Smart Fan I/II: tolerance */ -#define W83792D_SYSCTL_SF2_POINTS_FAN1 1602 /* Smart Fan II: Fan1 points */ -#define W83792D_SYSCTL_SF2_POINTS_FAN2 1603 /* Smart Fan II: Fan2 points */ -#define W83792D_SYSCTL_SF2_POINTS_FAN3 1604 /* Smart Fan II: Fan3 points */ -#define W83792D_SYSCTL_SF2_LEVELS_FAN1 1605 /* Smart Fan II: Fan1 levels */ -#define W83792D_SYSCTL_SF2_LEVELS_FAN2 1606 /* Smart Fan II: Fan2 levels */ -#define W83792D_SYSCTL_SF2_LEVELS_FAN3 1607 /* Smart Fan II: Fan3 levels */ - -#define W83792D_ALARM_IN0 0x0001 -#define W83792D_ALARM_IN1 0x0002 -#define W83792D_ALARM_IN2 0x0100 -#define W83792D_ALARM_IN3 0x0200 -#define W83792D_ALARM_IN4 0x0400 -#define W83792D_ALARM_IN5 0x0800 -#define W83792D_ALARM_IN6 0x1000 -#define W83792D_ALARM_IN7 0x80000 -#define W83792D_ALARM_IN8 0x100000 -#define W83792D_ALARM_TEMP1 0x0004 -#define W83792D_ALARM_TEMP2 0x0008 -#define W83792D_ALARM_TEMP3 0x0010 -#define W83792D_ALARM_FAN1 0x0020 -#define W83792D_ALARM_FAN2 0x0040 -#define W83792D_ALARM_FAN3 0x0080 -#define W83792D_ALARM_FAN4 0x200000 -#define W83792D_ALARM_FAN5 0x400000 -#define W83792D_ALARM_FAN6 0x800000 -#define W83792D_ALARM_FAN7 0x8000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for detected chip, - W83792D has 9 voltages 7 fans and 3 temperatures. */ -static ctl_table w83792d_dir_table_template[] = -{ - {W83792D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_in}, - {W83792D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_in}, - {W83792D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_in}, - {W83792D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_in}, - {W83792D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_in}, - {W83792D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_in}, - {W83792D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_in}, - {W83792D_SYSCTL_IN7, "in7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_in}, - {W83792D_SYSCTL_IN8, "in8", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_in}, - {W83792D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_fan}, - {W83792D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_fan}, - {W83792D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_fan}, - {W83792D_SYSCTL_FAN4, "fan4", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_fan}, - {W83792D_SYSCTL_FAN5, "fan5", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_fan}, - {W83792D_SYSCTL_FAN6, "fan6", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_fan}, - {W83792D_SYSCTL_FAN7, "fan7", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_fan}, - {W83792D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_temp}, - {W83792D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_temp_add}, - {W83792D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_temp_add}, - /*{W83792D_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_vid}, */ - {W83792D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_fan_div}, - {W83792D_SYSCTL_ALARMS, "alarms", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_alarms}, - {W83792D_SYSCTL_CHASSIS, "chassis", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_chassis}, - {W83792D_SYSCTL_PWM1, "pwm1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_pwm}, - {W83792D_SYSCTL_PWM2, "pwm2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_pwm}, - {W83792D_SYSCTL_PWM3, "pwm3", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_pwm}, - {W83792D_SYSCTL_PWM_FLAG, "pwm_flag", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_pwm_flag}, - {W83792D_SYSCTL_FAN_CFG, "fan_cfg", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_fan_cfg}, - /*{W83792D_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &w83792d_vrm}, */ - {W83792D_SYSCTL_THERMAL_CRUISE, "thermal_cruise", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_thermal_cruise}, - {W83792D_SYSCTL_FAN_TOLERANCE, "fan_tolerance", NULL, 0, 0644, - NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_fan_tolerance}, - {W83792D_SYSCTL_SF2_POINTS_FAN1, "sf2_points_fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_sf2_points}, - {W83792D_SYSCTL_SF2_POINTS_FAN2, "sf2_points_fan2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_sf2_points}, - {W83792D_SYSCTL_SF2_POINTS_FAN3, "sf2_points_fan3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_sf2_points}, - {W83792D_SYSCTL_SF2_LEVELS_FAN1, "sf2_levels_fan1", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_sf2_levels}, - {W83792D_SYSCTL_SF2_LEVELS_FAN2, "sf2_levels_fan2", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_sf2_levels}, - {W83792D_SYSCTL_SF2_LEVELS_FAN3, "sf2_levels_fan3", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83792d_sf2_levels}, - {0} -}; - -/* This function is called when: - * w83792d_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and w83792d_driver is still present) */ -static int w83792d_attach_adapter(struct i2c_adapter *adapter) -{ - int i_tmp; - ENTER() - i_tmp = i2c_detect(adapter, &addr_data, w83792d_detect); - LEAVE() - return i_tmp; -} - -static int -w83792d_create_subclient(struct i2c_adapter *adapter, - struct i2c_client *new_client, int addr, - struct i2c_client **sub_cli) -{ - int err; - struct i2c_client *sub_client; - - (*sub_cli) = sub_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!(sub_client)) { - return -ENOMEM; - } - memset(sub_client, 0x00, sizeof(struct i2c_client)); - sub_client->addr = 0x48 + addr; - sub_client->data = NULL; - sub_client->adapter = adapter; - sub_client->driver = &w83792d_driver; - sub_client->flags = 0; - strcpy(sub_client->name, "w83792d subclient"); - if ((err = i2c_attach_client(sub_client))) { - printk(KERN_ERR "w83792: subclient registration " - "at address 0x%x failed\n", sub_client->addr); - kfree(sub_client); - return err; - } - return 0; -} - -static int -w83792d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, - struct i2c_client *new_client) -{ - int i, id, err; - u8 val; - struct w83792d_data *data = new_client->data; - - data->lm75[0] = NULL; - data->lm75[1] = NULL; - - id = i2c_adapter_id(adapter); - if (force_subclients[0] == id && force_subclients[1] == address) { - for (i = 2; i <= 3; i++) { - if (force_subclients[i] < 0x48 || - force_subclients[i] > 0x4f) { - printk(KERN_ERR "w83792d: invalid subclient " - "address %d; must be 0x48-0x4f\n", - force_subclients[i]); - err = -ENODEV; - goto ERROR_SC_0; - } - } - w83792d_write_value(new_client, W83792D_REG_I2C_SUBADDR, - (force_subclients[2] & 0x07) | - ((force_subclients[3] & 0x07) << 4)); - } - - val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR); - if (!(val & 0x08)) { - err = w83792d_create_subclient(adapter, new_client, val & 0x7, - &data->lm75[0]); - if (err < 0) - goto ERROR_SC_0; - } - if (!(val & 0x80)) { - if ((data->lm75[0] != NULL) && - ((val & 0x7) == ((val >> 4) & 0x7))) { - printk(KERN_ERR "w83792d: duplicate addresses 0x%x, " - "use force_subclient\n", data->lm75[0]->addr); - err = -ENODEV; - goto ERROR_SC_1; - } - err = w83792d_create_subclient(adapter, new_client, - (val >> 4) & 0x7, &data->lm75[1]); - if (err < 0) - goto ERROR_SC_1; - } - - return 0; - -/* Undo inits in case of errors */ - -ERROR_SC_1: - if (data->lm75[0] != NULL) { - i2c_detach_client(data->lm75[0]); - kfree(data->lm75[0]); - } -ERROR_SC_0: - return err; -} - - -static int w83792d_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i, val1 = 0, val2 = 0; - struct i2c_client *new_client; - struct w83792d_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - ENTER() - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - LEAVE() - goto ERROR0; - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access w83792d_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct w83792d_data), GFP_KERNEL))) { - printk(KERN_ERR "w83792d: Out of memory in w83792d_detect (new_client).\n"); - err = -ENOMEM; - LEAVE() - goto ERROR0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &w83792d_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - if (kind < 0) { - if (w83792d_read_value(new_client, W83792D_REG_CONFIG)&0x80) { - LEAVE() - goto ERROR1; - } - val1 = w83792d_read_value(new_client, W83792D_REG_BANK); - val2 = w83792d_read_value(new_client, W83792D_REG_CHIPMAN); -#ifdef W83792D_DEBUG - printk(KERN_DEBUG "w83792d: val1 is: %d, val2 is: %d\n", - val1, val2); -#endif - /* Check for Winbond ID if in bank 0 */ - if (!(val1 & 0x07)) { /* is Bank0 */ - if (((!(val1 & 0x80)) && (val2 != 0xa3)) || - ((val1 & 0x80) && (val2 != 0x5c))) { - LEAVE() - goto ERROR1; - } - } - /* check address at 0x48. */ - if (w83792d_read_value(new_client, W83792D_REG_I2C_ADDR) - != address) { - LEAVE() - goto ERROR1; - } - } - - /* We have either had a force parameter, or we have already detected - the Winbond. Put it now into bank 0 and Vendor ID High Byte */ - w83792d_write_value(new_client, W83792D_REG_BANK, - (w83792d_read_value(new_client, - W83792D_REG_BANK) & 0x78) | - 0x80); - - /* Determine the chip type. */ - if (kind <= 0) { - /* get vendor ID */ - val2 = w83792d_read_value(new_client, W83792D_REG_CHIPMAN); - if (val2 != 0x5c) { /* the vendor is NOT Winbond */ - LEAVE() - goto ERROR1; - } - val1 = w83792d_read_value(new_client, W83792D_REG_WCHIPID); - if (val1 == 0x7a) { - kind = w83792d; - } else { - if (kind == 0) - printk(KERN_WARNING "w83792d: Ignoring " - "'force' parameter for unknown chip " - "at adapter %d, address 0x%02x\n", - i2c_adapter_id(adapter), address); - LEAVE() - goto ERROR1; - } - } - - if (kind == w83792d) { - type_name = "w83792d"; - client_name = "W83792D chip"; - } else { - printk(KERN_ERR "w83792d: Internal error: unknown kind (%d)?!?", - kind); - LEAVE() - goto ERROR1; - } - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - data->has_fan = 0x07; /* at least 3 fan inputs */ - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) { - LEAVE() - goto ERROR1; - } - - if ((err = w83792d_detect_subclients(adapter, address, - kind, new_client))) - goto ERROR2; - - /* Read GPIO enable register to check if pins for fan 4,5 are used as - GPIO */ - val1 = w83792d_read_value(new_client, W83792D_REG_GPIO_EN); - if (!(val1 & 0x40)) - data->has_fan |= 0x08; /* fan 4 */ - if (!(val1 & 0x20)) - data->has_fan |= 0x10; /* fan 5 */ - - val1 = w83792d_read_value(new_client, W83792D_REG_PIN); - if (val1 & 0x40) - data->has_fan |= 0x20; /* fan 6 */ - if (val1 & 0x04) - data->has_fan |= 0x40; /* fan 7 */ - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - w83792d_dir_table_template, THIS_MODULE)) < 0) { - err = i; - goto ERROR3; - } - data->sysctl_id = i; - - /* Initialize the chip */ - w83792d_init_client(new_client); - LEAVE() - return 0; - -ERROR3: - if (data->lm75[0] != NULL) { - i2c_detach_client(data->lm75[0]); - kfree(data->lm75[0]); - } - if (data->lm75[1] != NULL) { - i2c_detach_client(data->lm75[1]); - kfree(data->lm75[1]); - } -ERROR2: - i2c_detach_client(new_client); -ERROR1: - kfree(data); -ERROR0: - - LEAVE() - return err; -} - -static int w83792d_detach_client(struct i2c_client *client) -{ - int err; - struct w83792d_data *data = client->data; - ENTER() - - /* remove sysctl table (primary client only) */ - if ((data)) - i2c_deregister_entry(data->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR "w83792d: Client deregistration failed, client not detached.\n"); - LEAVE() - return err; - } - - if (data) { - /* primary client */ - kfree(data); - } else { - /* subclients */ - kfree(client); - } - - return 0; -} - -/* Called when we have found a new W83792D. */ -static void w83792d_init_client(struct i2c_client *client) -{ - int temp2_cfg, temp3_cfg; - u8 vid_in_b; - - ENTER() - - if (init) { - w83792d_write_value(client, W83792D_REG_CONFIG, 0x80); - } - /* data->vrm = 90; */ /* maybe need to be modified! */ - - /* Clear the bit6 of W83792D_REG_VID_IN_B(set it into 0): - W83792D_REG_VID_IN_B bit6 = 0: the high/low limit of - vin0/vin1 can be modified by user; - W83792D_REG_VID_IN_B bit6 = 1: the high/low limit of - vin0/vin1 auto-updated, can NOT be modified by user. */ - vid_in_b = w83792d_read_value(client, W83792D_REG_VID_IN_B); - w83792d_write_value(client, W83792D_REG_VID_IN_B, - vid_in_b & 0xbf); - - temp2_cfg = w83792d_read_value(client, W83792D_REG_TEMP_ADD[0][6]); - temp3_cfg = w83792d_read_value(client, W83792D_REG_TEMP_ADD[1][6]); - w83792d_write_value(client, W83792D_REG_TEMP_ADD[0][6], - temp2_cfg & 0xe6); - w83792d_write_value(client, W83792D_REG_TEMP_ADD[1][6], - temp3_cfg & 0xe6); - - /* Start monitoring */ - w83792d_write_value(client, W83792D_REG_CONFIG, (w83792d_read_value( - client, W83792D_REG_CONFIG) & 0xf7) | 0x01); - LEAVE() -} - -static void w83792d_update_client(struct i2c_client *client) -{ - struct w83792d_data *data = client->data; - int i, j; - u8 reg_array_tmp[4], pwm_array_tmp[7], reg_tmp; - - down(&data->update_lock); - - if (time_after(jiffies - data->last_updated, HZ * 3) || - time_before(jiffies, data->last_updated) || !data->valid) { - pr_debug(KERN_DEBUG "Starting device update\n"); - - /* Update the voltages measured value and limits */ - for (i = 0; i < 9; i++) { - data->in[i] = w83792d_read_value(client, - W83792D_REG_IN[i]); - data->in_max[i] = w83792d_read_value(client, - W83792D_REG_IN_MAX[i]); - data->in_min[i] = w83792d_read_value(client, - W83792D_REG_IN_MIN[i]); - } - data->low_bits = w83792d_read_value(client, - W83792D_REG_LOW_BITS1) + - (w83792d_read_value(client, - W83792D_REG_LOW_BITS2) << 8); - - for (i = 0; i < 7; i++) { - /* Update the Fan measured value and limits */ - data->fan[i] = w83792d_read_value(client, - W83792D_REG_FAN[i]); - data->fan_min[i] = w83792d_read_value(client, - W83792D_REG_FAN_MIN[i]); - /* Update the PWM/DC Value and PWM/DC flag */ - pwm_array_tmp[i] = w83792d_read_value(client, - W83792D_REG_PWM[i]); - data->pwm[i] = pwm_array_tmp[i] & 0x0f; - data->pwm_flag[i] = pwm_array_tmp[i] >> 7; - } - data->fan_cfg = w83792d_read_value(client, W83792D_REG_FAN_CFG); - - /* Update the Fan Divisor */ - for (i = 0; i < 4; i++) { - reg_array_tmp[i] = w83792d_read_value(client, W83792D_REG_FAN_DIV[i]); - } - data->fan_div[0] = reg_array_tmp[0] & 0x07; - data->fan_div[1] = (reg_array_tmp[0] >> 4) & 0x07; - data->fan_div[2] = reg_array_tmp[1] & 0x07; - data->fan_div[3] = (reg_array_tmp[1] >> 4) & 0x07; - data->fan_div[4] = reg_array_tmp[2] & 0x07; - data->fan_div[5] = (reg_array_tmp[2] >> 4) & 0x07; - data->fan_div[6] = reg_array_tmp[3] & 0x07; - - for (i = 0; i < 7; i++) { - if (!(data->has_fan & (1 << i))) - continue; - if (data->fan[i] == 0xff && data->fan_div[i] < 7) - w83792d_set_fan_div(client, i, 7); - else if (data->fan[i] < 0x70 && data->fan_div[i] > 0) { - w83792d_set_fan_div(client, i, - data->fan_div[i] - 1); - } else if (data->fan[i] > 0xf8 && - data->fan_div[i] < 7) { - w83792d_set_fan_div(client, i, - data->fan_div[i] + 1); - } - } - - /* Update the Temperature1 measured value and limits */ - data->temp1[0] = w83792d_read_value(client, W83792D_REG_TEMP1); - data->temp1[1] = w83792d_read_value(client, W83792D_REG_TEMP1_OVER); - data->temp1[2] = w83792d_read_value(client, W83792D_REG_TEMP1_HYST); - - /* Update the Temperature2/3 measured value and limits */ - for (i = 0; i < 7; i++) { - data->temp_add[0][i] = w83792d_read_value(client, - W83792D_REG_TEMP_ADD[0][i]); - data->temp_add[1][i] = w83792d_read_value(client, - W83792D_REG_TEMP_ADD[1][i]); - } - - /* Update the VID */ - /* i = w83792d_read_value(client, W83792D_REG_FAN_DIV[0]); - data->vid = i & 0x0f; - data->vid |= - (w83792d_read_value(client, W83792D_REG_CHIPID) & 0x01) - << 4; */ - - /* Update the realtime status */ - data->alarms = w83792d_read_value(client, W83792D_REG_ALARM1) + - (w83792d_read_value(client, W83792D_REG_ALARM2) << 8) + - (w83792d_read_value(client, W83792D_REG_ALARM3) << 16); - - /* Update CaseOpen status and it's CLR_CHS. */ - data->chassis[0] = (w83792d_read_value(client, - W83792D_REG_CASE_OPEN) - >> 5) & 0x01; - data->chassis[1] = (w83792d_read_value(client, - W83792D_REG_CASE_OPEN_CLR) - >> 7) & 0x01; - - /* Update Thermal Cruise/Smart Fan I target value */ - for (i = 0; i < 3; i++) { - data->thermal_cruise[i] = - w83792d_read_value(client, - W83792D_REG_THERMAL[i]) & 0x7f; - } - - /* Update Smart Fan I/II tolerance */ - reg_tmp = w83792d_read_value(client, W83792D_REG_FAN_TOL[0]); - data->fan_tolerance[0] = reg_tmp & 0x0f; - data->fan_tolerance[1] = (reg_tmp >> 4) & 0x0f; - data->fan_tolerance[2] = - w83792d_read_value(client, W83792D_REG_FAN_TOL[2]) & 0x0f; - - /* Update Smart Fan II temperature points */ - for (i = 0; i < 3; i++) { - for (j = 0; j < 4; j++) { - data->sf2_points[i][j] = w83792d_read_value( - client,W83792D_REG_POINTS[i][j]) & 0x7f; - } - } - - /* Update Smart Fan II duty cycle levels */ - for (i = 0; i < 3; i++) { - reg_tmp = w83792d_read_value(client, - W83792D_REG_LEVELS[i][0]); - data->sf2_levels[i][0] = reg_tmp & 0x0f; - data->sf2_levels[i][1] = (reg_tmp >> 4) & 0x0f; - reg_tmp = w83792d_read_value(client, - W83792D_REG_LEVELS[i][2]); - data->sf2_levels[i][2] = (reg_tmp >> 4) & 0x0f; - data->sf2_levels[i][3] = reg_tmp & 0x0f; - } - data->last_updated = jiffies; - data->valid = 1; -#ifdef W83792D_DEBUG - w83792d_print_debug(data); -#endif - } - up(&data->update_lock); -} - -/* This is a function used to debug the message. */ -#ifdef W83792D_DEBUG -static void w83792d_print_debug(struct w83792d_data *data) -{ - int i=0, j=0; - printk(KERN_DEBUG "==========The following is the debug message...========\n"); - printk(KERN_DEBUG "9 set of Voltages: =====>\n"); - for (i=0; i<=8; i++) { - printk(KERN_DEBUG "vin[%d] is: 0x%x\n", i, data->in[i]); - printk(KERN_DEBUG "vin[%d] max is: 0x%x\n", i, data->in_max[i]); - printk(KERN_DEBUG "vin[%d] min is: 0x%x\n", i, data->in_min[i]); - } - printk(KERN_DEBUG "Low Bit1 is: 0x%x\n", data->low_bits & 0xff); - printk(KERN_DEBUG "Low Bit2 is: 0x%x\n", data->low_bits >> 8); - printk(KERN_DEBUG "7 set of Fan Counts and 3 set of Duty Cycles: =====>\n"); - printk(KERN_DEBUG "fan_cfg is: 0x%x\n", data->fan_cfg); - for (i=0; i<=6; i++) { - printk(KERN_DEBUG "fan[%d] is: 0x%x\n", i, data->fan[i]); - printk(KERN_DEBUG "fan[%d] min is: 0x%x\n", i, data->fan_min[i]); - if (i<3) { - printk(KERN_DEBUG "pwm[%d] is: 0x%x\n", i, data->pwm[i]); - printk(KERN_DEBUG "pwm_flag[%d] is: 0x%x\n", i, data->pwm_flag[i]); - } - } - printk(KERN_DEBUG "3 set of Temperatures: =====>\n"); - printk(KERN_DEBUG "temp1 is: 0x%x\n", data->temp1[0]); - printk(KERN_DEBUG "temp1 high limit is: 0x%x\n", data->temp1[1]); - printk(KERN_DEBUG "temp1 low limit is: 0x%x\n", data->temp1[2]); - for (i=0; i<2; i++) { - for (j=0; j<7; j++) { - printk(KERN_DEBUG "temp_add[%d][%d] is: 0x%x\n", i, j, - data->temp_add[i][j]); - } - } - for (i=0; i<=6; i++) { - printk(KERN_DEBUG "fan_div[%d] is: 0x%x\n", i, data->fan_div[i]); - } - printk(KERN_DEBUG "==========End of the debug message...==================\n\n"); -} -#endif - -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ - -/* read/write voltage meaured value and limits */ -static void w83792d_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int nr = ctl_name - W83792D_SYSCTL_IN0; - - /* result[0]: low limit, result[1]: high limit, - result[2]: measured value */ - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - results[0] = IN_FROM_REG(nr, data->in_min[nr]*4); - results[1] = IN_FROM_REG(nr, data->in_max[nr]*4); - /* in7 and in8 do not have low bits, but the formula still - works */ - results[2] = IN_FROM_REG(nr, ((data->in[nr] << 2) | - ((data->low_bits >> (2 * nr)) - & 0x03))); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - /* Write Low limit into register. */ - data->in_min[nr] = SENSORS_LIMIT(IN_TO_REG(nr,results[0])/4, - 0, 255); - w83792d_write_value(client, W83792D_REG_IN_MIN[nr], - data->in_min[nr]); - } - if (*nrels_mag >= 2) { - /* Write High limit into register. */ - data->in_max[nr] = SENSORS_LIMIT(IN_TO_REG(nr,results[1])/4, - 0, 255); - w83792d_write_value(client, W83792D_REG_IN_MAX[nr], - data->in_max[nr]); - } - } -} - -static void w83792d_set_fan_div(struct i2c_client *client, int nr, u8 newdiv) -{ - struct w83792d_data *data = client->data; - int min, old; - u8 tmp; - - min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); - old = FAN_FROM_REG(data->fan[nr], DIV_FROM_REG(data->fan_div[nr])); - data->fan_div[nr] = newdiv; - tmp = w83792d_read_value(client, W83792D_REG_FAN_DIV[nr >> 1]); - tmp &= (nr & 1) ? 0x8f : 0xf8; - tmp |= (nr & 1) ? ((newdiv << 4) & 0x70) : (newdiv & 0x07); - w83792d_write_value(client, W83792D_REG_FAN_DIV[nr >> 1], tmp); - data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - data->fan[nr] = FAN_TO_REG(old, DIV_FROM_REG(data->fan_div[nr])); - w83792d_write_value(client, W83792D_REG_FAN_MIN[nr], - data->fan_min[nr]); -} - -/* read/write fan meaured value and limits */ -static void w83792d_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int nr = ctl_name - W83792D_SYSCTL_FAN1; - - /* result[0]: low limit, result[1]: measured value */ - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - if (data->has_fan & (1 << nr)) { - results[0] = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - results[1] = FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr])); - } else { - results[0] = 0; - results[1] = 0; - } - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1 && (data->has_fan & (1 << nr))) { - data->fan_min[nr] = FAN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr])); - w83792d_write_value(client, - W83792D_REG_FAN_MIN[nr], - data->fan_min[nr]); - } - } -} - -/* read/write temperature1 meaured value and limits */ -static void w83792d_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - - /* result[0]: high limit, result[1]: low limit - result[2]: measured value, the order is different with voltage(in) */ - if (operation == SENSORS_PROC_REAL_INFO) { - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - results[0] = TEMP_FROM_REG(data->temp1[1]); - results[1] = TEMP_FROM_REG(data->temp1[2]); - results[2] = TEMP_FROM_REG(data->temp1[0]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp1[1] = TEMP_TO_REG(results[0]); - w83792d_write_value(client, W83792D_REG_TEMP1_OVER, - data->temp1[1]); - } - if (*nrels_mag >= 2) { - data->temp1[2] = TEMP_TO_REG(results[1]); - w83792d_write_value(client, W83792D_REG_TEMP1_HYST, - data->temp1[2]); - } - } -} - -/* read/write temperature2,3 meaured value and limits */ -static void w83792d_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int nr = ctl_name - W83792D_SYSCTL_TEMP2; - int i=0, j=0; - - /* result[0]: high limit, result[1]: low limit - result[2]: measured value, the order is different with voltage(in) */ - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - for (i=0; i<3; i++) { - j = (i==0) ? 2 : ((i==1)?0:1); - if ((data->temp_add[nr][i*2+1]) & 0x80) { - results[j] = TEMP_FROM_REG(data->temp_add[nr][i*2]) + 5; - } else { - results[j] = TEMP_FROM_REG(data->temp_add[nr][i*2]); - } - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_add[nr][2] = TEMP_TO_REG(results[0]); - w83792d_write_value(client, - W83792D_REG_TEMP_ADD[nr][2], - data->temp_add[nr][2]); - if ((results[0]%10) == 0) { - w83792d_write_value(client, - W83792D_REG_TEMP_ADD[nr][3], 0x00); - } else { /* consider the 0.5 degree */ - w83792d_write_value(client, - W83792D_REG_TEMP_ADD[nr][3], 0x80); - } - } - if (*nrels_mag >= 2) { - data->temp_add[nr][4] = TEMP_TO_REG(results[1]); - w83792d_write_value(client, - W83792D_REG_TEMP_ADD[nr][4], - data->temp_add[nr][4]); - if ((results[1]%10) == 0) { - w83792d_write_value(client, - W83792D_REG_TEMP_ADD[nr][5], 0x00); - } else { /* consider the 0.5 degree */ - w83792d_write_value(client, - W83792D_REG_TEMP_ADD[nr][5], 0x80); - } - } - } -} - -/* -void w83792d_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - results[0] = vid_from_reg(data->vid, data->vrm); - *nrels_mag = 1; - } -} - -void w83792d_vrm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - results[0] = data->vrm; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->vrm = results[0]; - } - } -} */ - -/* Read/Write Fan Divisor */ -static void w83792d_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int i = 0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - for (i=0; i<7; i++) { - results[i] = DIV_FROM_REG(data->fan_div[i]); - } - *nrels_mag = 7; - } -} - - -/* Under Smart Fan I mode: read/write the Fan1/2/3 target temperature */ -static void w83792d_thermal_cruise(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int i=0; - u8 target_tmp=0, target_mask=0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - for (i=0; i<3; i++) { - results[i] = data->thermal_cruise[i]; - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - for (i=0; i<3; i++) { - if (*nrels_mag < (i+1)) { - return; - } - target_tmp = results[i]; - target_tmp = target_tmp & 0x7f; - target_mask = w83792d_read_value(client, - W83792D_REG_THERMAL[i]) & 0x80; - data->thermal_cruise[i] = SENSORS_LIMIT(target_tmp, 0, 255); - w83792d_write_value(client, W83792D_REG_THERMAL[i], - (data->thermal_cruise[i])|target_mask); - } - } -} - -/* The tolerance of fan1/fan2/fan3, when using Thermal Cruise(Smart Fan I) - or Smart Fan II mode. */ -static void w83792d_fan_tolerance(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int i=0; - u8 tol_tmp, tol_mask; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - for (i=0; i<3; i++) { - results[i] = data->fan_tolerance[i]; - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - for (i=0; i<3; i++) { - if (*nrels_mag < (i+1)) { - return; - } - tol_mask = w83792d_read_value(client, - W83792D_REG_FAN_TOL[i]) & ((i==1)?0x0f:0xf0); - tol_tmp = SENSORS_LIMIT(results[i], 0, 15); - tol_tmp &= 0x0f; - data->fan_tolerance[i] = tol_tmp; - if (i==1) { - tol_tmp <<= 4; - } - w83792d_write_value(client, W83792D_REG_FAN_TOL[i], - tol_mask|tol_tmp); - } - } -} - -/* Under Smart Fan II mode: read/write the Fan1/2/3 temperature points */ -static void w83792d_sf2_points(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int nr = ctl_name - W83792D_SYSCTL_SF2_POINTS_FAN1; - int j=0; - u8 mask_tmp = 0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - for (j=0; j<4; j++) { - results[j] = data->sf2_points[nr][j]; - } - *nrels_mag = 4; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - for (j=0; j<4; j++) { - if (*nrels_mag < (j+1)) { - return; - } - data->sf2_points[nr][j] = SENSORS_LIMIT(results[j], - 0, 127); - mask_tmp = w83792d_read_value(client, - W83792D_REG_POINTS[nr][j]) & 0x80; - w83792d_write_value(client, W83792D_REG_POINTS[nr][j], - mask_tmp|data->sf2_points[nr][j]); - } - } -} - -/* Smart Fan II Duty Cycle1/2/3 of Fan1/2/3. - Notice that: The Non-Stop can NOT be modified by user, - because it is related with some physical characters, - usually set by BIOS. User's modification to it may lead to - Fan's stop, then bring danger. */ -static void w83792d_sf2_levels(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int nr = ctl_name - W83792D_SYSCTL_SF2_LEVELS_FAN1; - int j = 0; - u8 mask_tmp = 0, level_tmp = 0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - for (j=0; j<4; j++) { - results[j] = (data->sf2_levels[nr][j] * 100) / 15; - } - *nrels_mag = 4; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - for (j=1; j<4; j++) { /* start with 1: need ignore Non-Stop */ - if (*nrels_mag < j) { - return; - } - data->sf2_levels[nr][j] = - SENSORS_LIMIT((results[j]*15)/100, 0, 15); - mask_tmp = w83792d_read_value(client, W83792D_REG_LEVELS[nr][j]) - & ((j==3) ? 0xf0 : 0x0f); - if (j==3) { - level_tmp = data->sf2_levels[nr][j]; - } else { - level_tmp = data->sf2_levels[nr][j] << 4; - } - w83792d_write_value(client, W83792D_REG_LEVELS[nr][j], - level_tmp | mask_tmp); - } - } -} - -/* get reatime status of all sensors items: voltage, temp, fan */ -static void w83792d_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - results[0] = data->alarms; - *nrels_mag = 1; - } -} - -/* Read/Write Chassis status and Reset Chassis. */ -static void w83792d_chassis(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - u8 temp1 = 0, temp2 = 0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - results[0] = data->chassis[0]; - results[1] = data->chassis[1]; - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - data->chassis[1] = SENSORS_LIMIT(results[1], 0 ,1); - temp1 = ((data->chassis[1]) << 7) & 0x80; - temp2 = w83792d_read_value(client, - W83792D_REG_CASE_OPEN_CLR) & 0x7f; - w83792d_write_value(client, - W83792D_REG_CASE_OPEN_CLR, - temp1|temp2); - } -} - -/* Read/Write PWM/DC value of Fan1,Fan2,Fan3, which controls the - Fan Duty Cycle */ -static void w83792d_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int nr = ctl_name - W83792D_SYSCTL_PWM1; - u8 pwm_mask; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - results[0] = data->pwm[nr] << 4; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - data->pwm[nr] = SENSORS_LIMIT(results[0], 0, 255) >> 4; - pwm_mask = w83792d_read_value(client,W83792D_REG_PWM[nr]) & 0xf0; - w83792d_write_value(client,W83792D_REG_PWM[nr],pwm_mask|data->pwm[nr]); - } -} - -/* Read/Write PWM/DC mode for Fan1,Fan2,Fan3: - 1->PWM mode, 0->DC mode */ -static void w83792d_pwm_flag(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - int i = 0; - u8 pwm_flag_mask; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - for (i=0; i<3; i++) { - results[i] = data->pwm_flag[i]; - } - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - for (i=0; i<3; i++) { - if (*nrels_mag < (i+1)) { - return; - } - data->pwm_flag[i] = SENSORS_LIMIT(results[i], 0, 1); - pwm_flag_mask = w83792d_read_value(client, - W83792D_REG_PWM[i]) & 0x7f; - w83792d_write_value(client, W83792D_REG_PWM[i], - ((data->pwm_flag[i])<<7)|pwm_flag_mask); - } - } -} - -/* Read/Write Fan mode into:PWM/DC, Thermal Cruise(SmartFanI), SmartFanII - 0->PWM/DC mode, 1->Thermal Cruise mode, 2/3->SmartFanII mode */ -static void w83792d_fan_cfg(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83792d_data *data = client->data; - u8 temp_cfg1, temp_cfg2, temp_cfg3, temp_cfg4; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83792d_update_client(client); - results[0] = (data->fan_cfg) & 0x03; /* Fan1's Mode */ - results[1] = ((data->fan_cfg)>>2) & 0x03; /* Fan2's Mode */ - results[2] = ((data->fan_cfg)>>4) & 0x03; /* Fan3's Mode */ - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag < 3) { - return; - } - temp_cfg1 = SENSORS_LIMIT(results[0], 0, 3); - temp_cfg2 = SENSORS_LIMIT(results[1], 0, 3) << 2; - temp_cfg3 = SENSORS_LIMIT(results[2], 0, 3) << 4; - temp_cfg4 = w83792d_read_value(client,W83792D_REG_FAN_CFG) & 0xc0; - data->fan_cfg = ((temp_cfg4|temp_cfg3)|temp_cfg2)|temp_cfg1; - w83792d_write_value(client,W83792D_REG_FAN_CFG,data->fan_cfg); - } -} - -static int __init sm_w83792d_init(void) -{ - ENTER() - - printk(KERN_INFO "w83792d version %s (%s)\n", LM_VERSION, LM_DATE); - - LEAVE() - return i2c_add_driver(&w83792d_driver); -} - -static void __exit sm_w83792d_exit(void) -{ - ENTER() - - i2c_del_driver(&w83792d_driver); - - LEAVE() -} - - -MODULE_AUTHOR("Chunhao Huang @ Winbond"); -MODULE_DESCRIPTION("W83792AD/D driver for linux-2.4"); -MODULE_LICENSE("GPL"); - -module_init(sm_w83792d_init); -module_exit(sm_w83792d_exit); - diff --git a/kernel/chips/w83l785ts.c b/kernel/chips/w83l785ts.c deleted file mode 100644 index f03d9fd4..00000000 --- a/kernel/chips/w83l785ts.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * w83l785ts.c - Part of lm_sensors, Linux kernel modules for hardware - * monitoring - * Copyright (C) 2003-2004 Jean Delvare - * - * Inspired from the lm83 driver. The W83L785TS-S is a sensor chip made - * by Winbond. It reports a single external temperature with a 1 deg - * resolution and a 3 deg accuracy. Data sheet can be obtained from - * Winbond's website at: - * http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf - * - * Thanks to James Bolt for benchmarking the read - * error handling mechanism. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include "version.h" - -#ifndef I2C_DRIVERID_W83L785TS -#define I2C_DRIVERID_W83L785TS 1047 -#endif - -/* How many retries on register read error */ -#define MAX_RETRIES 5 - -/* - * Address to scan - * Address is fully defined internally and cannot be changed. - */ - -static unsigned short normal_i2c[] = { 0x2e, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* - * Insmod parameters - */ - -SENSORS_INSMOD_1(w83l785ts); - -/* - * The W83L785TS-S registers - * Manufacturer ID is 0x5CA3 for Winbond. - */ - -#define W83L785TS_REG_MAN_ID1 0x4D -#define W83L785TS_REG_MAN_ID2 0x4C -#define W83L785TS_REG_CHIP_ID 0x4E -#define W83L785TS_REG_CONFIG 0x40 -#define W83L785TS_REG_TYPE 0x52 -#define W83L785TS_REG_TEMP 0x27 -#define W83L785TS_REG_TEMP_OVER 0x53 /* not sure about this one */ - -/* - * Conversions - * The W83L785TS-S uses signed 8-bit values. - */ - -#define TEMP_FROM_REG(val) (val) - -/* - * Functions declaration - */ - -static int w83l785ts_attach_adapter(struct i2c_adapter *adapter); -static int w83l785ts_detect(struct i2c_adapter *adapter, int address, unsigned - short flags, int kind); -static int w83l785ts_detach_client(struct i2c_client *client); -static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval); -static void w83l785ts_update_client(struct i2c_client *client); -static void w83l785ts_temp(struct i2c_client *client, int operation, int - ctl_name, int *nrels_mag, long *results); - -/* - * Driver data (common to all clients) - */ - -static struct i2c_driver w83l785ts_driver = { - .name = "W83L785S-S sensor driver", - .id = I2C_DRIVERID_W83L785TS, - .flags = I2C_DF_NOTIFY, - .attach_adapter = w83l785ts_attach_adapter, - .detach_client = w83l785ts_detach_client, -}; - -/* - * Client data (each client gets its own) - */ - -struct w83l785ts_data { - struct i2c_client client; - int sysctl_id; - - struct semaphore update_lock; - char valid; /* zero until following fields are valid */ - unsigned long last_updated; /* in jiffies */ - - /* registers values */ - s8 temp, temp_over; -}; - -/* - * Proc entries - * These files are created for each detected W83L785TS-S. - */ - -/* -- SENSORS SYSCTL START -- */ - -#define W83L785TS_SYSCTL_TEMP 1200 - -/* -- SENSORS SYSCTL END -- */ - - -static ctl_table w83l785ts_dir_table_template[] = -{ - {W83L785TS_SYSCTL_TEMP, "temp", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &w83l785ts_temp}, - {0} -}; - -/* - * Real code - */ - -static int w83l785ts_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, w83l785ts_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int w83l785ts_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - struct i2c_client *new_client; - struct w83l785ts_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { -#ifdef DEBUG - printk(KERN_DEBUG "w83l785ts.o: I2C bus doesn't support " - "byte read mode, skipping.\n"); -#endif - return 0; - } - - if (!(data = kmalloc(sizeof(struct w83l785ts_data), GFP_KERNEL))) { - printk(KERN_ERR "w83l785ts.o: Out of memory in w83l785ts_detect " - "(new_client).\n"); - return -ENOMEM; - } - - /* - * The common I2C client data is placed right after the - * W83L785TS-specific. The W83L785TS-specific data is pointed to by the - * data field from the I2C client data. - */ - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &w83l785ts_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip (actually there is only - * one possible kind of chip for now, W83L785TS-S). A zero kind means - * that the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - */ - - if (kind < 0) { /* detection */ - if (((w83l785ts_read_value(new_client, W83L785TS_REG_CONFIG, 0) - & 0x80) != 0x00) - || ((w83l785ts_read_value(new_client, W83L785TS_REG_TYPE, 0) - & 0xFC) != 0x00)) { -#ifdef DEBUG - printk(KERN_DEBUG "w83l785ts.o: Detection failed at " - "0x%02x.\n", address); -#endif - goto ERROR1; - } - } - - if (kind <= 0) { /* identification */ - u16 man_id; - u8 chip_id; - - man_id = (w83l785ts_read_value(new_client, W83L785TS_REG_MAN_ID1, 0) << 8) - + w83l785ts_read_value(new_client, W83L785TS_REG_MAN_ID2, 0); - chip_id = w83l785ts_read_value(new_client, W83L785TS_REG_CHIP_ID, 0); - if (man_id == 0x5CA3) { /* Winbond */ - if (chip_id == 0x70) - kind = w83l785ts; - } - } - - if (kind <= 0) { /* identification failed */ - printk(KERN_INFO "w83l785ts.o: Unsupported chip.\n"); - goto ERROR1; - } - - if (kind == w83l785ts) { - type_name = "w83l785ts"; - client_name = "W83L785TS-S chip"; - } else { - printk(KERN_ERR "w83l785ts.o: Unknown kind %d.\n", kind); - goto ERROR1; - } - - /* - * OK, we got a valid chip so we can fill in the remaining client - * fields. - */ - - strcpy(new_client->name, client_name); - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* - * Tell the I2C layer a new client has arrived. - */ - - if ((err = i2c_attach_client(new_client))) { -#ifdef DEBUG - printk(KERN_ERR "w83l785ts.o: Failed attaching client.\n"); -#endif - goto ERROR1; - } - - /* - * Register a new directory entry. - */ - - if ((err = i2c_register_entry(new_client, type_name, - w83l785ts_dir_table_template, THIS_MODULE)) < 0) { -#ifdef DEBUG - printk(KERN_ERR "w83l785ts.o: Failed registering directory " - "entry.\n"); -#endif - goto ERROR2; - } - data->sysctl_id = err; - - /* - * Initialize the W83L785TS chip - * Nothing yet, assume it is already started. - */ - - return 0; - - ERROR2: - i2c_detach_client(new_client); - ERROR1: - kfree(data); - return err; -} - -static int w83l785ts_detach_client(struct i2c_client *client) -{ - int err; - - i2c_deregister_entry(((struct w83l785ts_data *) (client->data))->sysctl_id); - if ((err = i2c_detach_client(client))) { - printk(KERN_ERR "w83l785ts.o: Client deregistration failed, " - "client not detached.\n"); - return err; - } - - kfree(client->data); - return 0; -} - -static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval) -{ - int value, i; - - /* Frequent read errors have been reported on Asus boards, so we - * retry on read errors. If it still fails (unlikely), return the - * default value requested by the caller. */ - for (i = 1; i <= MAX_RETRIES; i++) { - value = i2c_smbus_read_byte_data(client, reg); - if (value >= 0) - return value; - printk(KERN_WARNING "w83l785ts.o: Read failed, will retry " - "in %d.\n", i); - mdelay(i); - } - - printk(KERN_ERR "w83l785ts.o: Couldn't read value from register. " - "Please report.\n"); - return defval; -} - -static void w83l785ts_update_client(struct i2c_client *client) -{ - struct w83l785ts_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ * 2) - || (jiffies < data->last_updated) - || !data->valid) { -#ifdef DEBUG - printk(KERN_DEBUG "w83l785ts.o: Updating data.\n"); -#endif - data->temp = w83l785ts_read_value(client, W83L785TS_REG_TEMP, - data->temp); - data->temp_over = w83l785ts_read_value(client, - W83L785TS_REG_TEMP_OVER, data->temp_over); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -static void w83l785ts_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct w83l785ts_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) { - *nrels_mag = 0; /* magnitude */ - } else if (operation == SENSORS_PROC_REAL_READ) { - w83l785ts_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp); - *nrels_mag = 2; - } -} - -static int __init sm_w83l785ts_init(void) -{ - printk(KERN_INFO "w83l785ts.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&w83l785ts_driver); -} - -static void __exit sm_w83l785ts_exit(void) -{ - i2c_del_driver(&w83l785ts_driver); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("W83L785TS-S sensor driver"); -MODULE_LICENSE("GPL"); - -module_init(sm_w83l785ts_init); -module_exit(sm_w83l785ts_exit); diff --git a/kernel/chips/xeontemp.c b/kernel/chips/xeontemp.c deleted file mode 100644 index df97c887..00000000 --- a/kernel/chips/xeontemp.c +++ /dev/null @@ -1,383 +0,0 @@ -/* - xeontemp.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999,2003 Frodo Looijaard , - Philip Edelbrock , and - Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* The Xeon temperature sensor looks just like an ADM1021 with the remote - sensor only. There is are no ID registers so detection is difficult. */ - -#include -#include -#include -#include -#include -#include "version.h" - -#ifndef I2C_DRIVERID_XEONTEMP -#define I2C_DRIVERID_XEONTEMP 1045 -#endif - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x18, 0x1a, 0x29, 0x2b, - 0x4c, 0x4e, SENSORS_I2C_END -}; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; -static unsigned int normal_isa[] = { SENSORS_ISA_END }; -static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; - -/* Insmod parameters */ -SENSORS_INSMOD_1(xeontemp); - -/* xeontemp constants specified below */ - -/* The registers */ -/* Read-only */ -#define XEONTEMP_REG_REMOTE_TEMP 0x01 -#define XEONTEMP_REG_STATUS 0x02 -/* These use different addresses for reading/writing */ -#define XEONTEMP_REG_CONFIG_R 0x03 -#define XEONTEMP_REG_CONFIG_W 0x09 -#define XEONTEMP_REG_CONV_RATE_R 0x04 -#define XEONTEMP_REG_CONV_RATE_W 0x0A -/* limits */ -#define XEONTEMP_REG_REMOTE_TOS_R 0x07 -#define XEONTEMP_REG_REMOTE_TOS_W 0x0D -#define XEONTEMP_REG_REMOTE_THYST_R 0x08 -#define XEONTEMP_REG_REMOTE_THYST_W 0x0E -/* write-only */ -#define XEONTEMP_REG_ONESHOT 0x0F - -#define XEONTEMP_ALARM_RTEMP (XEONTEMP_ALARM_RTEMP_HIGH | XEONTEMP_ALARM_RTEMP_LOW\ - | XEONTEMP_ALARM_RTEMP_NA) -#define XEONTEMP_ALARM_ALL XEONTEMP_ALARM_RTEMP - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -/* Conversions note: 1021 uses normal integer signed-byte format*/ -#define TEMP_FROM_REG(val) (val > 127 ? val-256 : val) -#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? val+256 : val),0,255)) - -/* Each client has this additional data */ -struct xeontemp_data { - struct i2c_client client; - int sysctl_id; - enum chips type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 remote_temp, remote_temp_os, remote_temp_hyst, alarms; - u8 fail; -}; - -static int xeontemp_attach_adapter(struct i2c_adapter *adapter); -static int xeontemp_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static void xeontemp_init_client(struct i2c_client *client); -static int xeontemp_detach_client(struct i2c_client *client); -static int xeontemp_read_value(struct i2c_client *client, u8 reg); -static int xeontemp_rd_good(u8 *val, struct i2c_client *client, u8 reg, u8 mask); -static int xeontemp_write_value(struct i2c_client *client, u8 reg, - u16 value); -static void xeontemp_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, - long *results); -static void xeontemp_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void xeontemp_update_client(struct i2c_client *client); - -/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */ -static int read_only = 0; - - -/* This is the driver that will be inserted */ -static struct i2c_driver xeontemp_driver = { - .name = "Xeon temp sensor driver", - .id = I2C_DRIVERID_XEONTEMP, - .flags = I2C_DF_NOTIFY, - .attach_adapter = xeontemp_attach_adapter, - .detach_client = xeontemp_detach_client, -}; - -/* -- SENSORS SYSCTL START -- */ - -#define XEONTEMP_SYSCTL_REMOTE_TEMP 1201 -#define XEONTEMP_SYSCTL_ALARMS 1203 - -#define XEONTEMP_ALARM_RTEMP_HIGH 0x10 -#define XEONTEMP_ALARM_RTEMP_LOW 0x08 -#define XEONTEMP_ALARM_RTEMP_NA 0x04 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected xeontemp. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table xeontemp_dir_table_template[] = { - {XEONTEMP_SYSCTL_REMOTE_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &xeontemp_remote_temp}, - {XEONTEMP_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &xeontemp_alarms}, - {0} -}; - -static int xeontemp_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, xeontemp_detect); -} - -static int xeontemp_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int i; - struct i2c_client *new_client; - struct xeontemp_data *data; - int err = 0; - const char *type_name = ""; - const char *client_name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - goto error0; - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access xeontemp_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct xeontemp_data), GFP_KERNEL))) { - err = -ENOMEM; - goto error0; - } - - new_client = &data->client; - new_client->addr = address; - new_client->data = data; - new_client->adapter = adapter; - new_client->driver = &xeontemp_driver; - new_client->flags = 0; - - /* Now, we do the remaining detection. */ - - if (kind < 0) { - if ( - (xeontemp_read_value(new_client, XEONTEMP_REG_STATUS) & - 0x03) != 0x00) - goto error1; - } - - /* Determine the chip type. */ - - if (kind <= 0) { - kind = xeontemp; - } - - type_name = "xeontemp"; - client_name = "xeon sensors"; - - /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); - data->type = kind; - data->valid = 0; - init_MUTEX(&data->update_lock); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto error3; - - /* Register a new directory entry with module sensors */ - if ((i = i2c_register_entry(new_client, type_name, - xeontemp_dir_table_template, - THIS_MODULE)) < 0) { - err = i; - goto error4; - } - data->sysctl_id = i; - - xeontemp_init_client(new_client); - return 0; - - error4: - i2c_detach_client(new_client); - error3: - error1: - kfree(data); - error0: - return err; -} - -static void xeontemp_init_client(struct i2c_client *client) -{ - /* Enable ADC and disable suspend mode */ - xeontemp_write_value(client, XEONTEMP_REG_CONFIG_W, 0); - /* Set Conversion rate to 1/sec (this can be tinkered with) */ - xeontemp_write_value(client, XEONTEMP_REG_CONV_RATE_W, 0x04); -} - -static int xeontemp_detach_client(struct i2c_client *client) -{ - - int err; - - i2c_deregister_entry(((struct xeontemp_data *) (client->data))-> - sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk - ("xeontemp.o: Client deregistration failed, client not detached.\n"); - return err; - } - - kfree(client->data); - - return 0; - -} - - -/* All registers are byte-sized */ -static int xeontemp_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -/* only update value if read succeeded; set fail bit if failed */ -static int xeontemp_rd_good(u8 *val, struct i2c_client *client, u8 reg, u8 mask) -{ - int i; - struct xeontemp_data *data = client->data; - - i = i2c_smbus_read_byte_data(client, reg); - if (i < 0) { - data->fail |= mask; - return i; - } - *val = i; - return 0; -} - -static int xeontemp_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (read_only > 0) - return 0; - - return i2c_smbus_write_byte_data(client, reg, value); -} - -static void xeontemp_update_client(struct i2c_client *client) -{ - struct xeontemp_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { - -#ifdef DEBUG - printk("Starting xeontemp update\n"); -#endif - - data->fail = 0; - xeontemp_rd_good(&(data->remote_temp), client, - XEONTEMP_REG_REMOTE_TEMP, XEONTEMP_ALARM_RTEMP); - xeontemp_rd_good(&(data->remote_temp_os), client, - XEONTEMP_REG_REMOTE_TOS_R, XEONTEMP_ALARM_RTEMP); - xeontemp_rd_good(&(data->remote_temp_hyst), client, - XEONTEMP_REG_REMOTE_THYST_R, - XEONTEMP_ALARM_RTEMP); - data->alarms = XEONTEMP_ALARM_ALL; - if (!xeontemp_rd_good(&(data->alarms), client, - XEONTEMP_REG_STATUS, 0)) - data->alarms &= XEONTEMP_ALARM_ALL; - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - -void xeontemp_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct xeontemp_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - xeontemp_update_client(client); - results[0] = TEMP_FROM_REG(data->remote_temp_os); - results[1] = TEMP_FROM_REG(data->remote_temp_hyst); - results[2] = TEMP_FROM_REG(data->remote_temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->remote_temp_os = TEMP_TO_REG(results[0]); - xeontemp_write_value(client, - XEONTEMP_REG_REMOTE_TOS_W, - data->remote_temp_os); - } - if (*nrels_mag >= 2) { - data->remote_temp_hyst = TEMP_TO_REG(results[1]); - xeontemp_write_value(client, - XEONTEMP_REG_REMOTE_THYST_W, - data->remote_temp_hyst); - } - } -} - -void xeontemp_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct xeontemp_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - xeontemp_update_client(client); - results[0] = data->alarms | data->fail; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - /* Can't write to it */ - } -} - -static int __init sm_xeontemp_init(void) -{ - printk(KERN_INFO "xeontemp.o version %s (%s)\n", LM_VERSION, LM_DATE); - return i2c_add_driver(&xeontemp_driver); -} - -static void __exit sm_xeontemp_exit(void) -{ - i2c_del_driver(&xeontemp_driver); -} - -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("xeontemp driver"); -MODULE_LICENSE("GPL"); - -MODULE_PARM(read_only, "i"); -MODULE_PARM_DESC(read_only, "Don't set any values, read only mode"); - -module_init(sm_xeontemp_init) -module_exit(sm_xeontemp_exit) diff --git a/kernel/include/Module.mk b/kernel/include/Module.mk index e9702d0e..2f62f1ff 100644 --- a/kernel/include/Module.mk +++ b/kernel/include/Module.mk @@ -20,22 +20,9 @@ # verbatim in the rules, until it is redefined. MODULE_DIR := kernel/include KERNELINCLUDEDIR := $(MODULE_DIR) -KERNELCHIPSDIR := kernel/chips KERNELINCLUDEFILES := $(MODULE_DIR)/i2c-dev.h $(MODULE_DIR)/sensors.h -$(KERNELINCLUDEDIR)/sensors.h: $(KERNELINCLUDEDIR)/sensors.h.template - cat $@.template > $@ - $(AWK) '/SENSORS SYSCTL START/,/SENSORS SYSCTL END/' $(KERNELCHIPSDIR)/*.c >> $@ - echo '#endif' >> $@ - -$(KERNELINCLUDEDIR)/sensors.hd: - ( $(GREP) 'SENSORS SYSCTL START' /dev/null $(KERNELCHIPSDIR)/*.c | \ - $(SED) -e 's/:.*//' -e 's#^#$(KERNELINCLUDEDIR)/sensors.h: #' ) > $@ - -# Get dependencies of sensors.h -INCLUDEFILES += $(MODULE_DIR)/sensors.hd - REMOVEKERNELINC := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(SYSINCLUDEDIR)/%,$(KERNELINCLUDEFILES)) install-all-kernel-include: @@ -50,8 +37,3 @@ user_uninstall:: $(RM) $(REMOVEKERNELINC) # Remove directory if empty, ignore failure $(RMDIR) $(DESTDIR)$(SYSINCLUDEDIR) 2> /dev/null || true - -clean-all-kernel-include: - $(RM) $(KERNELINCLUDEDIR)/*.h.install $(KERNELINCLUDEDIR)/sensors.h $(KERNELINCLUDEDIR)/sensors.hd - -clean :: clean-all-kernel-include diff --git a/kernel/include/ds1307.h b/kernel/include/ds1307.h deleted file mode 100644 index add9b123..00000000 --- a/kernel/include/ds1307.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef DS1307_H -#define DS1307_H - -/* - * linux/include/linux/ds1307.h - * - * Author: Abraham van der Merwe - * - * Linux support for the Dallas Semiconductor DS1307 Serial Real-Time - * Clock. - * - * Based on code from the lm-sensors project which is available - * at http://www.lm-sensors.org/ and Russell King's PCF8583 Real-Time - * Clock driver (linux/drivers/acorn/char/pcf8583.c). - * - * This source code is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - */ - -#include - -/* practically the same as struct rtc_time, but without tm_yday and tm_isdst */ -struct ds1307_date { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; -}; - -struct ds1307_memory { - u8 offset; /* 0 - 55 */ - u8 buf[56]; /* data */ - u8 length; /* offset + length <= 50 */ -}; - -/* size of the rtc non-volatile ram */ -#define DS1307_SIZE 56 - -/* the following frequencies are supported */ -#define DS1307_FREQ_1HZ 1 -#define DS1307_FREQ_4KHZ 4096 -#define DS1307_FREQ_8KHZ 8192 -#define DS1307_FREQ_32KHZ 32768 - -#define DS1307_GET_DATE _IOR ('d',0,struct ds1307_date *) -#define DS1307_SET_DATE _IOW ('d',1,struct ds1307_date *) -#define DS1307_IRQ_ON _IO ('d',2) -#define DS1307_IRQ_OFF _IO ('d',3) -#define DS1307_GET_FREQ _IOR ('d',4,u16 *) -#define DS1307_SET_FREQ _IOW ('d',5,u16 *) -#define DS1307_READ _IOR ('d',6,struct ds1307_memory *) -#define DS1307_WRITE _IOW ('d',7,struct ds1307_memory *) -#define DS1307_ENABLE _IO ('d',8) - -#endif /* #ifdef DS1307_H */ diff --git a/kernel/include/sensors.h b/kernel/include/sensors.h new file mode 100644 index 00000000..b077ae3f --- /dev/null +++ b/kernel/include/sensors.h @@ -0,0 +1,1608 @@ +/* + sensors.h - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef LIB_SENSORS_H +#define LIB_SENSORS_H + +/* This file is intended to be included from userland utilities only. + * It used to be generated from kernel driver code, but the new sysfs + * standard interface makes these definitions obsolete. For now, we will be + * keeping the old defintions in this file, until all applications have + * been upgraded to the new model (dynamic discovery of chip features.) + */ + + +/* From linux/i2c-proc.h */ + +/* Sysctl IDs */ +#ifdef DEV_HWMON +#define DEV_SENSORS DEV_HWMON +#else /* ndef DEV_HWMOM */ +#define DEV_SENSORS 2 /* The id of the lm_sensors directory within the + dev table */ +#endif /* def DEV_HWMON */ + +/* The maximum length of the prefix */ +#define SENSORS_PREFIX_MAX 20 + +#define SENSORS_CHIPS 1 +struct i2c_chips_data { + int sysctl_id; + char name[SENSORS_PREFIX_MAX + 13]; +}; + + +/* -- SENSORS SYSCTL START -- */ + +#define ADM1021_SYSCTL_TEMP 1200 +#define ADM1021_SYSCTL_REMOTE_TEMP 1201 +#define ADM1021_SYSCTL_DIE_CODE 1202 +#define ADM1021_SYSCTL_ALARMS 1203 + +#define ADM1021_ALARM_TEMP_HIGH 0x40 +#define ADM1021_ALARM_TEMP_LOW 0x20 +#define ADM1021_ALARM_RTEMP_HIGH 0x10 +#define ADM1021_ALARM_RTEMP_LOW 0x08 +#define ADM1021_ALARM_RTEMP_NA 0x04 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define ADM1024_SYSCTL_IN0 1000 /* Volts * 100 */ +#define ADM1024_SYSCTL_IN1 1001 +#define ADM1024_SYSCTL_IN2 1002 +#define ADM1024_SYSCTL_IN3 1003 +#define ADM1024_SYSCTL_IN4 1004 +#define ADM1024_SYSCTL_IN5 1005 +#define ADM1024_SYSCTL_FAN1 1101 /* Rotations/min */ +#define ADM1024_SYSCTL_FAN2 1102 +#define ADM1024_SYSCTL_TEMP 1250 /* Degrees Celsius * 100 */ +#define ADM1024_SYSCTL_TEMP1 1290 /* Degrees Celsius */ +#define ADM1024_SYSCTL_TEMP2 1295 /* Degrees Celsius */ +#define ADM1024_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define ADM1024_SYSCTL_ALARMS 2001 /* bitvector */ +#define ADM1024_SYSCTL_ANALOG_OUT 2002 +#define ADM1024_SYSCTL_VID 2003 + +#define ADM1024_ALARM_IN0 0x0001 +#define ADM1024_ALARM_IN1 0x0002 +#define ADM1024_ALARM_IN2 0x0004 +#define ADM1024_ALARM_IN3 0x0008 +#define ADM1024_ALARM_IN4 0x0100 +#define ADM1024_ALARM_IN5 0x0200 +#define ADM1024_ALARM_FAN1 0x0040 +#define ADM1024_ALARM_FAN2 0x0080 +#define ADM1024_ALARM_TEMP 0x0010 +#define ADM1024_ALARM_TEMP1 0x0020 +#define ADM1024_ALARM_TEMP2 0x0001 +#define ADM1024_ALARM_CHAS 0x1000 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define ADM1025_SYSCTL_IN0 1000 /* Volts * 100 */ +#define ADM1025_SYSCTL_IN1 1001 +#define ADM1025_SYSCTL_IN2 1002 +#define ADM1025_SYSCTL_IN3 1003 +#define ADM1025_SYSCTL_IN4 1004 +#define ADM1025_SYSCTL_IN5 1005 + +#define ADM1025_SYSCTL_RTEMP 1250 /* Degrees Celsius * 10 */ +#define ADM1025_SYSCTL_TEMP 1251 + +#define ADM1025_SYSCTL_ALARMS 2001 /* bitvector */ +#define ADM1025_SYSCTL_VID 2003 /* Volts * 1000 */ +#define ADM1025_SYSCTL_VRM 2004 + +#define ADM1025_ALARM_IN0 0x0001 +#define ADM1025_ALARM_IN1 0x0002 +#define ADM1025_ALARM_IN2 0x0004 +#define ADM1025_ALARM_IN3 0x0008 +#define ADM1025_ALARM_IN4 0x0100 +#define ADM1025_ALARM_IN5 0x0200 +#define ADM1025_ALARM_RTEMP 0x0020 +#define ADM1025_ALARM_TEMP 0x0010 +#define ADM1025_ALARM_RFAULT 0x4000 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define ADM1026_SYSCTL_FAN0 1000 +#define ADM1026_SYSCTL_FAN1 1001 +#define ADM1026_SYSCTL_FAN2 1002 +#define ADM1026_SYSCTL_FAN3 1003 +#define ADM1026_SYSCTL_FAN4 1004 +#define ADM1026_SYSCTL_FAN5 1005 +#define ADM1026_SYSCTL_FAN6 1006 +#define ADM1026_SYSCTL_FAN7 1007 +#define ADM1026_SYSCTL_FAN_DIV 1008 +#define ADM1026_SYSCTL_GPIO 1009 +#define ADM1026_SYSCTL_GPIO_MASK 1010 +#define ADM1026_SYSCTL_ALARMS 1011 +#define ADM1026_SYSCTL_ALARM_MASK 1012 +#define ADM1026_SYSCTL_IN0 1013 +#define ADM1026_SYSCTL_IN1 1014 +#define ADM1026_SYSCTL_IN2 1015 +#define ADM1026_SYSCTL_IN3 1016 +#define ADM1026_SYSCTL_IN4 1017 +#define ADM1026_SYSCTL_IN5 1018 +#define ADM1026_SYSCTL_IN6 1019 +#define ADM1026_SYSCTL_IN7 1020 +#define ADM1026_SYSCTL_IN8 1021 +#define ADM1026_SYSCTL_IN9 1022 +#define ADM1026_SYSCTL_IN10 1023 +#define ADM1026_SYSCTL_IN11 1024 +#define ADM1026_SYSCTL_IN12 1025 +#define ADM1026_SYSCTL_IN13 1026 +#define ADM1026_SYSCTL_IN14 1027 +#define ADM1026_SYSCTL_IN15 1028 +#define ADM1026_SYSCTL_IN16 1029 +#define ADM1026_SYSCTL_PWM 1030 +#define ADM1026_SYSCTL_ANALOG_OUT 1031 +#define ADM1026_SYSCTL_AFC 1032 +#define ADM1026_SYSCTL_TEMP1 1033 +#define ADM1026_SYSCTL_TEMP2 1034 +#define ADM1026_SYSCTL_TEMP3 1035 +#define ADM1026_SYSCTL_TEMP_OFFSET1 1036 +#define ADM1026_SYSCTL_TEMP_OFFSET2 1037 +#define ADM1026_SYSCTL_TEMP_OFFSET3 1038 +#define ADM1026_SYSCTL_TEMP_THERM1 1039 +#define ADM1026_SYSCTL_TEMP_THERM2 1040 +#define ADM1026_SYSCTL_TEMP_THERM3 1041 +#define ADM1026_SYSCTL_TEMP_TMIN1 1042 +#define ADM1026_SYSCTL_TEMP_TMIN2 1043 +#define ADM1026_SYSCTL_TEMP_TMIN3 1044 +#define ADM1026_SYSCTL_VID 1045 +#define ADM1026_SYSCTL_VRM 1046 + +#define ADM1026_ALARM_TEMP2 (1L << 0) +#define ADM1026_ALARM_TEMP3 (1L << 1) +#define ADM1026_ALARM_IN9 (1L << 1) +#define ADM1026_ALARM_IN11 (1L << 2) +#define ADM1026_ALARM_IN12 (1L << 3) +#define ADM1026_ALARM_IN13 (1L << 4) +#define ADM1026_ALARM_IN14 (1L << 5) +#define ADM1026_ALARM_IN15 (1L << 6) +#define ADM1026_ALARM_IN16 (1L << 7) +#define ADM1026_ALARM_IN0 (1L << 8) +#define ADM1026_ALARM_IN1 (1L << 9) +#define ADM1026_ALARM_IN2 (1L << 10) +#define ADM1026_ALARM_IN3 (1L << 11) +#define ADM1026_ALARM_IN4 (1L << 12) +#define ADM1026_ALARM_IN5 (1L << 13) +#define ADM1026_ALARM_IN6 (1L << 14) +#define ADM1026_ALARM_IN7 (1L << 15) +#define ADM1026_ALARM_FAN0 (1L << 16) +#define ADM1026_ALARM_FAN1 (1L << 17) +#define ADM1026_ALARM_FAN2 (1L << 18) +#define ADM1026_ALARM_FAN3 (1L << 19) +#define ADM1026_ALARM_FAN4 (1L << 20) +#define ADM1026_ALARM_FAN5 (1L << 21) +#define ADM1026_ALARM_FAN6 (1L << 22) +#define ADM1026_ALARM_FAN7 (1L << 23) +#define ADM1026_ALARM_TEMP1 (1L << 24) +#define ADM1026_ALARM_IN10 (1L << 25) +#define ADM1026_ALARM_IN8 (1L << 26) +#define ADM1026_ALARM_THERM (1L << 27) +#define ADM1026_ALARM_AFC_FAN (1L << 28) +#define ADM1026_ALARM_UNUSED (1L << 29) +#define ADM1026_ALARM_CI (1L << 30) +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define ADM1031_SYSCTL_TEMP1 1200 +#define ADM1031_SYSCTL_TEMP2 1201 +#define ADM1031_SYSCTL_TEMP3 1202 + +#define ADM1031_SYSCTL_FAN1 1210 +#define ADM1031_SYSCTL_FAN2 1211 + +#define ADM1031_SYSCTL_FAN_DIV 1220 + +#define ADM1031_SYSCTL_ALARMS 1250 + +#define ADM1031_ALARM_FAN1_MIN 0x0001 +#define ADM1031_ALARM_FAN1_FLT 0x0002 +#define ADM1031_ALARM_TEMP2_HIGH 0x0004 +#define ADM1031_ALARM_TEMP2_LOW 0x0008 +#define ADM1031_ALARM_TEMP2_CRIT 0x0010 +#define ADM1031_ALARM_TEMP2_DIODE 0x0020 +#define ADM1031_ALARM_TEMP1_HIGH 0x0040 +#define ADM1031_ALARM_TEMP1_LOW 0x0080 +#define ADM1031_ALARM_FAN2_MIN 0x0100 +#define ADM1031_ALARM_FAN2_FLT 0x0200 +#define ADM1031_ALARM_TEMP3_HIGH 0x0400 +#define ADM1031_ALARM_TEMP3_LOW 0x0800 +#define ADM1031_ALARM_TEMP3_CRIT 0x1000 +#define ADM1031_ALARM_TEMP3_DIODE 0x2000 +#define ADM1031_ALARM_TEMP1_CRIT 0x4000 +#define ADM1031_ALARM_THERMAL 0x8000 + + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define ADM9240_SYSCTL_IN0 1000 /* Volts * 100 */ +#define ADM9240_SYSCTL_IN1 1001 +#define ADM9240_SYSCTL_IN2 1002 +#define ADM9240_SYSCTL_IN3 1003 +#define ADM9240_SYSCTL_IN4 1004 +#define ADM9240_SYSCTL_IN5 1005 +#define ADM9240_SYSCTL_FAN1 1101 /* Rotations/min */ +#define ADM9240_SYSCTL_FAN2 1102 +#define ADM9240_SYSCTL_TEMP 1250 /* Degrees Celsius * 100 */ +#define ADM9240_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define ADM9240_SYSCTL_ALARMS 2001 /* bitvector */ +#define ADM9240_SYSCTL_ANALOG_OUT 2002 +#define ADM9240_SYSCTL_VID 2003 + +#define ADM9240_ALARM_IN0 0x0001 +#define ADM9240_ALARM_IN1 0x0002 +#define ADM9240_ALARM_IN2 0x0004 +#define ADM9240_ALARM_IN3 0x0008 +#define ADM9240_ALARM_IN4 0x0100 +#define ADM9240_ALARM_IN5 0x0200 +#define ADM9240_ALARM_FAN1 0x0040 +#define ADM9240_ALARM_FAN2 0x0080 +#define ADM9240_ALARM_TEMP 0x0010 +#define ADM9240_ALARM_CHAS 0x1000 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define ASB100_SYSCTL_IN0 1000 /* Volts * 100 */ +#define ASB100_SYSCTL_IN1 1001 +#define ASB100_SYSCTL_IN2 1002 +#define ASB100_SYSCTL_IN3 1003 +#define ASB100_SYSCTL_IN4 1004 +#define ASB100_SYSCTL_IN5 1005 +#define ASB100_SYSCTL_IN6 1006 + +#define ASB100_SYSCTL_FAN1 1101 /* Rotations/min */ +#define ASB100_SYSCTL_FAN2 1102 +#define ASB100_SYSCTL_FAN3 1103 + +#define ASB100_SYSCTL_TEMP1 1200 /* Degrees Celsius * 10 */ +#define ASB100_SYSCTL_TEMP2 1201 +#define ASB100_SYSCTL_TEMP3 1202 +#define ASB100_SYSCTL_TEMP4 1203 + +#define ASB100_SYSCTL_VID 1300 /* Volts * 1000 */ +#define ASB100_SYSCTL_VRM 1301 + +#define ASB100_SYSCTL_PWM1 1401 /* 0-255 => 0-100% duty cycle */ + +#define ASB100_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define ASB100_SYSCTL_ALARMS 2001 /* bitvector */ + +#define ASB100_ALARM_IN0 0x0001 /* ? */ +#define ASB100_ALARM_IN1 0x0002 /* ? */ +#define ASB100_ALARM_IN2 0x0004 +#define ASB100_ALARM_IN3 0x0008 +#define ASB100_ALARM_TEMP1 0x0010 +#define ASB100_ALARM_TEMP2 0x0020 +#define ASB100_ALARM_FAN1 0x0040 +#define ASB100_ALARM_FAN2 0x0080 +#define ASB100_ALARM_IN4 0x0100 +#define ASB100_ALARM_IN5 0x0200 /* ? */ +#define ASB100_ALARM_IN6 0x0400 /* ? */ +#define ASB100_ALARM_FAN3 0x0800 +#define ASB100_ALARM_CHAS 0x1000 +#define ASB100_ALARM_TEMP3 0x2000 + +#define ASB100_ALARM_IN7 0x10000 /* ? */ +#define ASB100_ALARM_IN8 0x20000 /* ? */ + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define BMC_SYSCTL_IN1 1000 +#define BMC_SYSCTL_TEMP1 1100 +#define BMC_SYSCTL_CURR1 1200 +#define BMC_SYSCTL_FAN1 1300 +#define BMC_SYSCTL_ALARMS 5000 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define BT869_SYSCTL_STATUS 1000 +#define BT869_SYSCTL_NTSC 1001 +#define BT869_SYSCTL_HALF 1002 +#define BT869_SYSCTL_RES 1003 +#define BT869_SYSCTL_COLORBARS 1004 +#define BT869_SYSCTL_DEPTH 1005 +#define BT869_SYSCTL_SVIDEO 1006 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define DDCMON_SYSCTL_ID 1010 +#define DDCMON_SYSCTL_SIZE 1011 +#define DDCMON_SYSCTL_SYNC 1012 +#define DDCMON_SYSCTL_TIMINGS 1013 +#define DDCMON_SYSCTL_SERIAL 1014 +#define DDCMON_SYSCTL_TIME 1015 +#define DDCMON_SYSCTL_EDID 1016 +#define DDCMON_SYSCTL_GAMMA 1017 +#define DDCMON_SYSCTL_DPMS 1018 +#define DDCMON_SYSCTL_TIMING1 1021 +#define DDCMON_SYSCTL_TIMING2 1022 +#define DDCMON_SYSCTL_TIMING3 1023 +#define DDCMON_SYSCTL_TIMING4 1024 +#define DDCMON_SYSCTL_TIMING5 1025 +#define DDCMON_SYSCTL_TIMING6 1026 +#define DDCMON_SYSCTL_TIMING7 1027 +#define DDCMON_SYSCTL_TIMING8 1028 +#define DDCMON_SYSCTL_MAXCLOCK 1029 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define DS1621_SYSCTL_TEMP 1200 /* Degrees Celsius * 10 */ +#define DS1621_SYSCTL_ALARMS 2001 /* bitvector */ +#define DS1621_ALARM_TEMP_HIGH 0x40 +#define DS1621_ALARM_TEMP_LOW 0x20 +#define DS1621_SYSCTL_ENABLE 2002 +#define DS1621_SYSCTL_CONTINUOUS 2003 +#define DS1621_SYSCTL_POLARITY 2004 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define EEPROM_SYSCTL1 1000 +#define EEPROM_SYSCTL2 1001 +#define EEPROM_SYSCTL3 1002 +#define EEPROM_SYSCTL4 1003 +#define EEPROM_SYSCTL5 1004 +#define EEPROM_SYSCTL6 1005 +#define EEPROM_SYSCTL7 1006 +#define EEPROM_SYSCTL8 1007 +#define EEPROM_SYSCTL9 1008 +#define EEPROM_SYSCTL10 1009 +#define EEPROM_SYSCTL11 1010 +#define EEPROM_SYSCTL12 1011 +#define EEPROM_SYSCTL13 1012 +#define EEPROM_SYSCTL14 1013 +#define EEPROM_SYSCTL15 1014 +#define EEPROM_SYSCTL16 1015 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define F71805F_SYSCTL_IN0 1000 +#define F71805F_SYSCTL_IN1 1001 +#define F71805F_SYSCTL_IN2 1002 +#define F71805F_SYSCTL_IN3 1003 +#define F71805F_SYSCTL_IN4 1004 +#define F71805F_SYSCTL_IN5 1005 +#define F71805F_SYSCTL_IN6 1006 +#define F71805F_SYSCTL_IN7 1007 +#define F71805F_SYSCTL_IN8 1008 +#define F71805F_SYSCTL_FAN1 1101 +#define F71805F_SYSCTL_FAN2 1102 +#define F71805F_SYSCTL_FAN3 1103 +#define F71805F_SYSCTL_TEMP1 1201 +#define F71805F_SYSCTL_TEMP2 1202 +#define F71805F_SYSCTL_TEMP3 1203 +#define F71805F_SYSCTL_SENSOR1 1211 +#define F71805F_SYSCTL_SENSOR2 1212 +#define F71805F_SYSCTL_SENSOR3 1213 +#define F71805F_SYSCTL_ALARMS_IN 1090 +#define F71805F_SYSCTL_ALARMS_FAN 1190 +#define F71805F_SYSCTL_ALARMS_TEMP 1290 +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define FSCHER_SYSCTL_VOLT0 1000 /* 12 volt supply */ +#define FSCHER_SYSCTL_VOLT1 1001 /* 5 volt supply */ +#define FSCHER_SYSCTL_VOLT2 1002 /* batterie voltage */ +#define FSCHER_SYSCTL_FAN0 1101 /* state, ripple, actual value + fan 0 */ +#define FSCHER_SYSCTL_FAN1 1102 /* state, ripple, actual value + fan 1 */ +#define FSCHER_SYSCTL_FAN2 1103 /* state, ripple, actual value + fan 2 */ +#define FSCHER_SYSCTL_TEMP0 1201 /* state and value of sensor 0, + cpu die */ +#define FSCHER_SYSCTL_TEMP1 1202 /* state and value of sensor 1, + motherboard */ +#define FSCHER_SYSCTL_TEMP2 1203 /* state and value of sensor 2, + chassis */ +#define FSCHER_SYSCTL_PWM0 1301 /* min fan 0 */ +#define FSCHER_SYSCTL_PWM1 1302 /* min fan 1 */ +#define FSCHER_SYSCTL_PWM2 1303 /* min fan 2 */ +#define FSCHER_SYSCTL_REV 2000 /* revision */ +#define FSCHER_SYSCTL_EVENT 2001 /* global event status */ +#define FSCHER_SYSCTL_CONTROL 2002 /* global control byte */ +#define FSCHER_SYSCTL_WDOG 2003 /* watch dog preset, state and + control */ +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define FSCPOS_SYSCTL_VOLT0 1000 /* 12 volt supply */ +#define FSCPOS_SYSCTL_VOLT1 1001 /* 5 volt supply */ +#define FSCPOS_SYSCTL_VOLT2 1002 /* batterie voltage*/ +#define FSCPOS_SYSCTL_FAN0 1101 /* state, min, ripple, actual value fan 0 */ +#define FSCPOS_SYSCTL_FAN1 1102 /* state, min, ripple, actual value fan 1 */ +#define FSCPOS_SYSCTL_FAN2 1103 /* state, min, ripple, actual value fan 2 */ +#define FSCPOS_SYSCTL_TEMP0 1201 /* state and value of sensor 0, cpu die */ +#define FSCPOS_SYSCTL_TEMP1 1202 /* state and value of sensor 1, motherboard */ +#define FSCPOS_SYSCTL_TEMP2 1203 /* state and value of sensor 2, chassis */ +#define FSCPOS_SYSCTL_REV 2000 /* Revision */ +#define FSCPOS_SYSCTL_EVENT 2001 /* global event status */ +#define FSCPOS_SYSCTL_CONTROL 2002 /* global control byte */ +#define FSCPOS_SYSCTL_WDOG 2003 /* state, min, ripple, actual value fan 2 */ +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define FSCSCY_SYSCTL_VOLT0 1000 /* 12 volt supply */ +#define FSCSCY_SYSCTL_VOLT1 1001 /* 5 volt supply */ +#define FSCSCY_SYSCTL_VOLT2 1002 /* batterie voltage*/ +#define FSCSCY_SYSCTL_FAN0 1101 /* state, min, ripple, actual value fan 0 */ +#define FSCSCY_SYSCTL_FAN1 1102 /* state, min, ripple, actual value fan 1 */ +#define FSCSCY_SYSCTL_FAN2 1103 /* state, min, ripple, actual value fan 2 */ +#define FSCSCY_SYSCTL_FAN3 1104 /* state, min, ripple, actual value fan 3 */ +#define FSCSCY_SYSCTL_FAN4 1105 /* state, min, ripple, actual value fan 4 */ +#define FSCSCY_SYSCTL_FAN5 1106 /* state, min, ripple, actual value fan 5 */ +#define FSCSCY_SYSCTL_TEMP0 1201 /* state and value of sensor 0, cpu die */ +#define FSCSCY_SYSCTL_TEMP1 1202 /* state and value of sensor 1, motherboard */ +#define FSCSCY_SYSCTL_TEMP2 1203 /* state and value of sensor 2, chassis */ +#define FSCSCY_SYSCTL_TEMP3 1204 /* state and value of sensor 3, chassis */ +#define FSCSCY_SYSCTL_REV 2000 /* Revision */ +#define FSCSCY_SYSCTL_EVENT 2001 /* global event status */ +#define FSCSCY_SYSCTL_CONTROL 2002 /* global control byte */ +#define FSCSCY_SYSCTL_WDOG 2003 /* state, min, ripple, actual value fan 2 */ +#define FSCSCY_SYSCTL_PCILOAD 2004 /* PCILoad value */ +#define FSCSCY_SYSCTL_INTRUSION 2005 /* state, control for intrusion sensor */ + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define GL518_SYSCTL_VDD 1000 /* Volts * 100 */ +#define GL518_SYSCTL_VIN1 1001 +#define GL518_SYSCTL_VIN2 1002 +#define GL518_SYSCTL_VIN3 1003 +#define GL518_SYSCTL_FAN1 1101 /* RPM */ +#define GL518_SYSCTL_FAN2 1102 +#define GL518_SYSCTL_TEMP 1200 /* Degrees Celsius * 10 */ +#define GL518_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define GL518_SYSCTL_ALARMS 2001 /* bitvector */ +#define GL518_SYSCTL_BEEP 2002 /* bitvector */ +#define GL518_SYSCTL_FAN1OFF 2003 +#define GL518_SYSCTL_ITERATE 2004 + +#define GL518_ALARM_VDD 0x01 +#define GL518_ALARM_VIN1 0x02 +#define GL518_ALARM_VIN2 0x04 +#define GL518_ALARM_VIN3 0x08 +#define GL518_ALARM_TEMP 0x10 +#define GL518_ALARM_FAN1 0x20 +#define GL518_ALARM_FAN2 0x40 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define GL520_SYSCTL_VDD 1000 /* Volts * 100 */ +#define GL520_SYSCTL_VIN1 1001 +#define GL520_SYSCTL_VIN2 1002 +#define GL520_SYSCTL_VIN3 1003 +#define GL520_SYSCTL_VIN4 1004 +#define GL520_SYSCTL_FAN1 1101 /* RPM */ +#define GL520_SYSCTL_FAN2 1102 +#define GL520_SYSCTL_TEMP1 1200 /* Degrees Celsius * 10 */ +#define GL520_SYSCTL_TEMP2 1201 /* Degrees Celsius * 10 */ +#define GL520_SYSCTL_VID 1300 +#define GL520_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define GL520_SYSCTL_ALARMS 2001 /* bitvector */ +#define GL520_SYSCTL_BEEP 2002 /* bitvector */ +#define GL520_SYSCTL_FAN1OFF 2003 +#define GL520_SYSCTL_CONFIG 2004 + +#define GL520_ALARM_VDD 0x01 +#define GL520_ALARM_VIN1 0x02 +#define GL520_ALARM_VIN2 0x04 +#define GL520_ALARM_VIN3 0x08 +#define GL520_ALARM_TEMP1 0x10 +#define GL520_ALARM_FAN1 0x20 +#define GL520_ALARM_FAN2 0x40 +#define GL520_ALARM_TEMP2 0x80 +#define GL520_ALARM_VIN4 0x80 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define IT87_SYSCTL_IN0 1000 /* Volts * 100 */ +#define IT87_SYSCTL_IN1 1001 +#define IT87_SYSCTL_IN2 1002 +#define IT87_SYSCTL_IN3 1003 +#define IT87_SYSCTL_IN4 1004 +#define IT87_SYSCTL_IN5 1005 +#define IT87_SYSCTL_IN6 1006 +#define IT87_SYSCTL_IN7 1007 +#define IT87_SYSCTL_IN8 1008 +#define IT87_SYSCTL_FAN1 1101 /* Rotations/min */ +#define IT87_SYSCTL_FAN2 1102 +#define IT87_SYSCTL_FAN3 1103 +#define IT87_SYSCTL_TEMP1 1200 /* Degrees Celsius * 10 */ +#define IT87_SYSCTL_TEMP2 1201 /* Degrees Celsius * 10 */ +#define IT87_SYSCTL_TEMP3 1202 /* Degrees Celsius * 10 */ +#define IT87_SYSCTL_VID 1300 /* Volts * 100 */ +#define IT87_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define IT87_SYSCTL_ALARMS 2004 /* bitvector */ + +#define IT87_SYSCTL_PWM1 1401 +#define IT87_SYSCTL_PWM2 1402 +#define IT87_SYSCTL_PWM3 1403 +#define IT87_SYSCTL_FAN_CTL 1501 +#define IT87_SYSCTL_FAN_ON_OFF 1502 +#define IT87_SYSCTL_SENS1 1601 /* 1, 2, or Beta (3000-5000) */ +#define IT87_SYSCTL_SENS2 1602 +#define IT87_SYSCTL_SENS3 1603 + +#define IT87_ALARM_IN0 0x000100 +#define IT87_ALARM_IN1 0x000200 +#define IT87_ALARM_IN2 0x000400 +#define IT87_ALARM_IN3 0x000800 +#define IT87_ALARM_IN4 0x001000 +#define IT87_ALARM_IN5 0x002000 +#define IT87_ALARM_IN6 0x004000 +#define IT87_ALARM_IN7 0x008000 +#define IT87_ALARM_FAN1 0x0001 +#define IT87_ALARM_FAN2 0x0002 +#define IT87_ALARM_FAN3 0x0004 +#define IT87_ALARM_TEMP1 0x00010000 +#define IT87_ALARM_TEMP2 0x00020000 +#define IT87_ALARM_TEMP3 0x00040000 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define LM63_SYSCTL_TEMP1 1200 +#define LM63_SYSCTL_TEMP2 1201 +#define LM63_SYSCTL_TEMP2_TCRIT 1205 +#define LM63_SYSCTL_TEMP2_TCRIT_HYST 1208 +#define LM63_SYSCTL_ALARMS 1210 +#define LM63_SYSCTL_FAN1 1220 +#define LM63_SYSCTL_PWM1 1230 + +#define LM63_ALARM_LOCAL_HIGH 0x40 +#define LM63_ALARM_REMOTE_HIGH 0x10 +#define LM63_ALARM_REMOTE_LOW 0x08 +#define LM63_ALARM_REMOTE_CRIT 0x02 +#define LM63_ALARM_REMOTE_OPEN 0x04 +#define LM63_ALARM_FAN_LOW 0x01 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define LM75_SYSCTL_TEMP 1200 /* Degrees Celsius * 10 */ + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define LM78_SYSCTL_IN0 1000 /* Volts * 100 */ +#define LM78_SYSCTL_IN1 1001 +#define LM78_SYSCTL_IN2 1002 +#define LM78_SYSCTL_IN3 1003 +#define LM78_SYSCTL_IN4 1004 +#define LM78_SYSCTL_IN5 1005 +#define LM78_SYSCTL_IN6 1006 +#define LM78_SYSCTL_FAN1 1101 /* Rotations/min */ +#define LM78_SYSCTL_FAN2 1102 +#define LM78_SYSCTL_FAN3 1103 +#define LM78_SYSCTL_TEMP 1200 /* Degrees Celsius * 10 */ +#define LM78_SYSCTL_VID 1300 /* Volts * 100 */ +#define LM78_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define LM78_SYSCTL_ALARMS 2001 /* bitvector */ + +#define LM78_ALARM_IN0 0x0001 +#define LM78_ALARM_IN1 0x0002 +#define LM78_ALARM_IN2 0x0004 +#define LM78_ALARM_IN3 0x0008 +#define LM78_ALARM_IN4 0x0100 +#define LM78_ALARM_IN5 0x0200 +#define LM78_ALARM_IN6 0x0400 +#define LM78_ALARM_FAN1 0x0040 +#define LM78_ALARM_FAN2 0x0080 +#define LM78_ALARM_FAN3 0x0800 +#define LM78_ALARM_TEMP 0x0010 +#define LM78_ALARM_BTI 0x0020 +#define LM78_ALARM_CHAS 0x1000 +#define LM78_ALARM_FIFO 0x2000 +#define LM78_ALARM_SMI_IN 0x4000 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define LM80_SYSCTL_IN0 1000 /* Volts * 100 */ +#define LM80_SYSCTL_IN1 1001 +#define LM80_SYSCTL_IN2 1002 +#define LM80_SYSCTL_IN3 1003 +#define LM80_SYSCTL_IN4 1004 +#define LM80_SYSCTL_IN5 1005 +#define LM80_SYSCTL_IN6 1006 +#define LM80_SYSCTL_FAN1 1101 /* Rotations/min */ +#define LM80_SYSCTL_FAN2 1102 +#define LM80_SYSCTL_TEMP 1250 /* Degrees Celsius * 100 */ +#define LM80_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define LM80_SYSCTL_ALARMS 2001 /* bitvector */ + +#define LM80_ALARM_IN0 0x0001 +#define LM80_ALARM_IN1 0x0002 +#define LM80_ALARM_IN2 0x0004 +#define LM80_ALARM_IN3 0x0008 +#define LM80_ALARM_IN4 0x0010 +#define LM80_ALARM_IN5 0x0020 +#define LM80_ALARM_IN6 0x0040 +#define LM80_ALARM_FAN1 0x0400 +#define LM80_ALARM_FAN2 0x0800 +#define LM80_ALARM_TEMP_HOT 0x0100 +#define LM80_ALARM_TEMP_OS 0x2000 +#define LM80_ALARM_CHAS 0x1000 +#define LM80_ALARM_BTI 0x0200 +#define LM80_ALARM_INT_IN 0x0080 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define LM83_SYSCTL_LOCAL_TEMP 1200 +#define LM83_SYSCTL_REMOTE1_TEMP 1201 +#define LM83_SYSCTL_REMOTE2_TEMP 1202 +#define LM83_SYSCTL_REMOTE3_TEMP 1203 +#define LM83_SYSCTL_TCRIT 1208 +#define LM83_SYSCTL_ALARMS 1210 + +#define LM83_ALARM_LOCAL_HIGH 0x0040 +#define LM83_ALARM_LOCAL_CRIT 0x0001 +#define LM83_ALARM_REMOTE1_HIGH 0x8000 +#define LM83_ALARM_REMOTE1_CRIT 0x0100 +#define LM83_ALARM_REMOTE1_OPEN 0x2000 +#define LM83_ALARM_REMOTE2_HIGH 0x0010 +#define LM83_ALARM_REMOTE2_CRIT 0x0002 +#define LM83_ALARM_REMOTE2_OPEN 0x0004 +#define LM83_ALARM_REMOTE3_HIGH 0x1000 +#define LM83_ALARM_REMOTE3_CRIT 0x0200 +#define LM83_ALARM_REMOTE3_OPEN 0x0400 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +/* Common parameters */ +#define LM85_SYSCTL_IN0 1000 +#define LM85_SYSCTL_IN1 1001 +#define LM85_SYSCTL_IN2 1002 +#define LM85_SYSCTL_IN3 1003 +#define LM85_SYSCTL_IN4 1004 +#define LM85_SYSCTL_FAN1 1005 +#define LM85_SYSCTL_FAN2 1006 +#define LM85_SYSCTL_FAN3 1007 +#define LM85_SYSCTL_FAN4 1008 +#define LM85_SYSCTL_TEMP1 1009 +#define LM85_SYSCTL_TEMP2 1010 +#define LM85_SYSCTL_TEMP3 1011 +#define LM85_SYSCTL_VID 1012 +#define LM85_SYSCTL_ALARMS 1013 +#define LM85_SYSCTL_PWM1 1014 +#define LM85_SYSCTL_PWM2 1015 +#define LM85_SYSCTL_PWM3 1016 +#define LM85_SYSCTL_VRM 1017 +#define LM85_SYSCTL_PWM_CFG1 1019 +#define LM85_SYSCTL_PWM_CFG2 1020 +#define LM85_SYSCTL_PWM_CFG3 1021 +#define LM85_SYSCTL_PWM_ZONE1 1022 +#define LM85_SYSCTL_PWM_ZONE2 1023 +#define LM85_SYSCTL_PWM_ZONE3 1024 +#define LM85_SYSCTL_ZONE1 1025 +#define LM85_SYSCTL_ZONE2 1026 +#define LM85_SYSCTL_ZONE3 1027 +#define LM85_SYSCTL_SMOOTH1 1028 +#define LM85_SYSCTL_SMOOTH2 1029 +#define LM85_SYSCTL_SMOOTH3 1030 + +/* Vendor specific values */ +#define LM85_SYSCTL_SPINUP_CTL 1100 +#define LM85_SYSCTL_TACH_MODE 1101 + +/* Analog Devices variant of the LM85 */ +#define ADM1027_SYSCTL_TACH_MODE 1200 +#define ADM1027_SYSCTL_TEMP_OFFSET1 1201 +#define ADM1027_SYSCTL_TEMP_OFFSET2 1202 +#define ADM1027_SYSCTL_TEMP_OFFSET3 1203 +#define ADM1027_SYSCTL_FAN_PPR 1204 +#define ADM1027_SYSCTL_ALARM_MASK 1205 + +/* Analog Devices variant of the LM85/ADM1027 */ +#define ADT7463_SYSCTL_TMIN_CTL1 1300 +#define ADT7463_SYSCTL_TMIN_CTL2 1301 +#define ADT7463_SYSCTL_TMIN_CTL3 1302 +#define ADT7463_SYSCTL_THERM_SIGNAL 1303 + +/* SMSC variant of the LM85 */ +#define EMC6D100_SYSCTL_IN5 1400 +#define EMC6D100_SYSCTL_IN6 1401 +#define EMC6D100_SYSCTL_IN7 1402 + +#define LM85_ALARM_IN0 0x0001 +#define LM85_ALARM_IN1 0x0002 +#define LM85_ALARM_IN2 0x0004 +#define LM85_ALARM_IN3 0x0008 +#define LM85_ALARM_TEMP1 0x0010 +#define LM85_ALARM_TEMP2 0x0020 +#define LM85_ALARM_TEMP3 0x0040 +#define LM85_ALARM_ALARM2 0x0080 +#define LM85_ALARM_IN4 0x0100 +#define LM85_ALARM_RESERVED 0x0200 +#define LM85_ALARM_FAN1 0x0400 +#define LM85_ALARM_FAN2 0x0800 +#define LM85_ALARM_FAN3 0x1000 +#define LM85_ALARM_FAN4 0x2000 +#define LM85_ALARM_TEMP1_FAULT 0x4000 +#define LM85_ALARM_TEMP3_FAULT 0x08000 +#define LM85_ALARM_IN6 0x10000 +#define LM85_ALARM_IN7 0x20000 +#define LM85_ALARM_IN5 0x40000 +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define LM87_SYSCTL_IN0 1000 /* Volts * 100 */ +#define LM87_SYSCTL_IN1 1001 +#define LM87_SYSCTL_IN2 1002 +#define LM87_SYSCTL_IN3 1003 +#define LM87_SYSCTL_IN4 1004 +#define LM87_SYSCTL_IN5 1005 +#define LM87_SYSCTL_AIN1 1006 +#define LM87_SYSCTL_AIN2 1007 +#define LM87_SYSCTL_FAN1 1102 +#define LM87_SYSCTL_FAN2 1103 +#define LM87_SYSCTL_TEMP1 1250 /* Degrees Celsius * 10 */ +#define LM87_SYSCTL_TEMP2 1251 /* Degrees Celsius * 10 */ +#define LM87_SYSCTL_TEMP3 1252 /* Degrees Celsius * 10 */ +#define LM87_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define LM87_SYSCTL_ALARMS 2001 /* bitvector */ +#define LM87_SYSCTL_ANALOG_OUT 2002 +#define LM87_SYSCTL_VID 2003 +#define LM87_SYSCTL_VRM 2004 + +#define LM87_ALARM_IN0 0x0001 +#define LM87_ALARM_IN1 0x0002 +#define LM87_ALARM_IN2 0x0004 +#define LM87_ALARM_IN3 0x0008 +#define LM87_ALARM_TEMP1 0x0010 +#define LM87_ALARM_TEMP2 0x0020 +#define LM87_ALARM_TEMP3 0x0020 /* same?? */ +#define LM87_ALARM_FAN1 0x0040 +#define LM87_ALARM_FAN2 0x0080 +#define LM87_ALARM_IN4 0x0100 +#define LM87_ALARM_IN5 0x0200 +#define LM87_ALARM_RESERVED1 0x0400 +#define LM87_ALARM_RESERVED2 0x0800 +#define LM87_ALARM_CHAS 0x1000 +#define LM87_ALARM_THERM_SIG 0x2000 +#define LM87_ALARM_TEMP2_FAULT 0x4000 +#define LM87_ALARM_TEMP3_FAULT 0x08000 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define LM90_SYSCTL_LOCAL_TEMP 1200 +#define LM90_SYSCTL_REMOTE_TEMP 1201 +#define LM90_SYSCTL_LOCAL_TCRIT 1204 +#define LM90_SYSCTL_REMOTE_TCRIT 1205 +#define LM90_SYSCTL_LOCAL_HYST 1207 +#define LM90_SYSCTL_REMOTE_HYST 1208 +#define LM90_SYSCTL_ALARMS 1210 +#define LM90_SYSCTL_PEC 1214 + +#define LM90_ALARM_LOCAL_HIGH 0x40 +#define LM90_ALARM_LOCAL_LOW 0x20 +#define LM90_ALARM_LOCAL_CRIT 0x01 +#define LM90_ALARM_REMOTE_HIGH 0x10 +#define LM90_ALARM_REMOTE_LOW 0x08 +#define LM90_ALARM_REMOTE_CRIT 0x02 +#define LM90_ALARM_REMOTE_OPEN 0x04 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define LM92_SYSCTL_ALARMS 2001 /* high, low, critical */ +#define LM92_SYSCTL_TEMP 1200 /* high, low, critical, hysteresis, input */ + +#define LM92_ALARM_TEMP_HIGH 0x01 +#define LM92_ALARM_TEMP_LOW 0x02 +#define LM92_ALARM_TEMP_CRIT 0x04 +#define LM92_TEMP_HIGH 0x08 +#define LM92_TEMP_LOW 0x10 +#define LM92_TEMP_CRIT 0x20 +#define LM92_TEMP_HYST 0x40 +#define LM92_TEMP_INPUT 0x80 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +/* volts * 100 */ +#define LM93_SYSCTL_IN1 1001 +#define LM93_SYSCTL_IN2 1002 +#define LM93_SYSCTL_IN3 1003 +#define LM93_SYSCTL_IN4 1004 +#define LM93_SYSCTL_IN5 1005 +#define LM93_SYSCTL_IN6 1006 +#define LM93_SYSCTL_IN7 1007 +#define LM93_SYSCTL_IN8 1008 +#define LM93_SYSCTL_IN9 1009 +#define LM93_SYSCTL_IN10 1010 +#define LM93_SYSCTL_IN11 1011 +#define LM93_SYSCTL_IN12 1012 +#define LM93_SYSCTL_IN13 1013 +#define LM93_SYSCTL_IN14 1014 +#define LM93_SYSCTL_IN15 1015 +#define LM93_SYSCTL_IN16 1016 + +/* degrees Celsius * 10 */ +#define LM93_SYSCTL_TEMP1 1101 +#define LM93_SYSCTL_TEMP2 1102 +#define LM93_SYSCTL_TEMP3 1103 + +#define LM93_SYSCTL_TEMP1_AUTO_BASE 1111 +#define LM93_SYSCTL_TEMP2_AUTO_BASE 1112 +#define LM93_SYSCTL_TEMP3_AUTO_BASE 1113 + +#define LM93_SYSCTL_TEMP1_AUTO_OFFSETS 1121 +#define LM93_SYSCTL_TEMP2_AUTO_OFFSETS 1122 +#define LM93_SYSCTL_TEMP3_AUTO_OFFSETS 1123 + +#define LM93_SYSCTL_TEMP1_AUTO_BOOST 1131 +#define LM93_SYSCTL_TEMP2_AUTO_BOOST 1132 +#define LM93_SYSCTL_TEMP3_AUTO_BOOST 1133 + +#define LM93_SYSCTL_TEMP1_AUTO_BOOST_HYST 1141 +#define LM93_SYSCTL_TEMP2_AUTO_BOOST_HYST 1142 +#define LM93_SYSCTL_TEMP3_AUTO_BOOST_HYST 1143 + +/* 0 => off, 255 => 100% */ +#define LM93_SYSCTL_TEMP1_AUTO_PWM_MIN 1151 +#define LM93_SYSCTL_TEMP2_AUTO_PWM_MIN 1152 +#define LM93_SYSCTL_TEMP3_AUTO_PWM_MIN 1153 + +/* degrees Celsius * 10 */ +#define LM93_SYSCTL_TEMP1_AUTO_OFFSET_HYST 1161 +#define LM93_SYSCTL_TEMP2_AUTO_OFFSET_HYST 1162 +#define LM93_SYSCTL_TEMP3_AUTO_OFFSET_HYST 1163 + +/* rotations/minute */ +#define LM93_SYSCTL_FAN1 1201 +#define LM93_SYSCTL_FAN2 1202 +#define LM93_SYSCTL_FAN3 1203 +#define LM93_SYSCTL_FAN4 1204 + +/* 1-2 => enable smart tach mode associated with this pwm #, or disable */ +#define LM93_SYSCTL_FAN1_SMART_TACH 1205 +#define LM93_SYSCTL_FAN2_SMART_TACH 1206 +#define LM93_SYSCTL_FAN3_SMART_TACH 1207 +#define LM93_SYSCTL_FAN4_SMART_TACH 1208 + +/* volts * 1000 */ +#define LM93_SYSCTL_VID1 1301 +#define LM93_SYSCTL_VID2 1302 + +/* 0 => off, 255 => 100% */ +#define LM93_SYSCTL_PWM1 1401 +#define LM93_SYSCTL_PWM2 1402 + +/* Hz */ +#define LM93_SYSCTL_PWM1_FREQ 1411 +#define LM93_SYSCTL_PWM2_FREQ 1412 + +/* bitvector */ +#define LM93_SYSCTL_PWM1_AUTO_CHANNELS 1421 +#define LM93_SYSCTL_PWM2_AUTO_CHANNELS 1422 + +/* Hz */ +#define LM93_SYSCTL_PWM1_AUTO_SPINUP_MIN 1431 +#define LM93_SYSCTL_PWM2_AUTO_SPINUP_MIN 1432 + +/* seconds */ +#define LM93_SYSCTL_PWM1_AUTO_SPINUP_TIME 1441 +#define LM93_SYSCTL_PWM2_AUTO_SPINUP_TIME 1442 + +/* seconds */ +#define LM93_SYSCTL_PWM_AUTO_PROCHOT_RAMP 1451 +#define LM93_SYSCTL_PWM_AUTO_VRDHOT_RAMP 1452 + +/* 0 => 0%, 255 => > 99.6% */ +#define LM93_SYSCTL_PROCHOT1 1501 +#define LM93_SYSCTL_PROCHOT2 1502 + +/* !0 => enable #PROCHOT logical short */ +#define LM93_SYSCTL_PROCHOT_SHORT 1503 + +/* 2 boolean enable/disable, 3rd value indicates duty cycle */ +#define LM93_SYSCTL_PROCHOT_OVERRIDE 1504 + +/* 2 values, 0-9 */ +#define LM93_SYSCTL_PROCHOT_INTERVAL 1505 + +/* GPIO input (bitmask) */ +#define LM93_SYSCTL_GPIO 1601 + +/* #VRDHOT input (boolean) */ +#define LM93_SYSCTL_VRDHOT1 1701 +#define LM93_SYSCTL_VRDHOT2 1702 + +/* alarms (bitmask) */ +#define LM93_SYSCTL_ALARMS 2001 + +/* alarm bitmask definitions + The LM93 has nearly 64 bits of error status... I've pared that down to + what I think is a useful subset in order to fit it into 32 bits. + + Especially note that the #VRD_HOT alarms are missing because we provide + that information as values in another /proc file. + + If libsensors is extended to support 64 bit values, this could be revisited. +*/ +#define LM93_ALARM_IN1 0x00000001 +#define LM93_ALARM_IN2 0x00000002 +#define LM93_ALARM_IN3 0x00000004 +#define LM93_ALARM_IN4 0x00000008 +#define LM93_ALARM_IN5 0x00000010 +#define LM93_ALARM_IN6 0x00000020 +#define LM93_ALARM_IN7 0x00000040 +#define LM93_ALARM_IN8 0x00000080 +#define LM93_ALARM_IN9 0x00000100 +#define LM93_ALARM_IN10 0x00000200 +#define LM93_ALARM_IN11 0x00000400 +#define LM93_ALARM_IN12 0x00000800 +#define LM93_ALARM_IN13 0x00001000 +#define LM93_ALARM_IN14 0x00002000 +#define LM93_ALARM_IN15 0x00004000 +#define LM93_ALARM_IN16 0x00008000 +#define LM93_ALARM_FAN1 0x00010000 +#define LM93_ALARM_FAN2 0x00020000 +#define LM93_ALARM_FAN3 0x00040000 +#define LM93_ALARM_FAN4 0x00080000 +#define LM93_ALARM_PH1_ERR 0x00100000 +#define LM93_ALARM_PH2_ERR 0x00200000 +#define LM93_ALARM_SCSI1_ERR 0x00400000 +#define LM93_ALARM_SCSI2_ERR 0x00800000 +#define LM93_ALARM_DVDDP1_ERR 0x01000000 +#define LM93_ALARM_DVDDP2_ERR 0x02000000 +#define LM93_ALARM_D1_ERR 0x04000000 +#define LM93_ALARM_D2_ERR 0x08000000 +#define LM93_ALARM_TEMP1 0x10000000 +#define LM93_ALARM_TEMP2 0x20000000 +#define LM93_ALARM_TEMP3 0x40000000 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define LTC1710_SYSCTL_SWITCH_1 1000 +#define LTC1710_SYSCTL_SWITCH_2 1001 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define MATORB_SYSCTL_DISP 1000 +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define MAX1619_SYSCTL_LOCAL_TEMP 1200 +#define MAX1619_SYSCTL_REMOTE_TEMP 1201 +#define MAX1619_SYSCTL_REMOTE_CRIT 1202 +#define MAX1619_SYSCTL_ALARMS 1203 + +#define MAX1619_ALARM_REMOTE_THIGH 0x10 +#define MAX1619_ALARM_REMOTE_TLOW 0x08 +#define MAX1619_ALARM_REMOTE_OPEN 0x04 +#define MAX1619_ALARM_REMOTE_OVERT 0x02 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define MAX6650_SYSCTL_FAN1 1101 +#define MAX6650_SYSCTL_FAN2 1102 +#define MAX6650_SYSCTL_FAN3 1103 +#define MAX6650_SYSCTL_FAN4 1104 +#define MAX6650_SYSCTL_SPEED 1105 +#define MAX6650_SYSCTL_XDUMP 1106 + + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define MAXI_SYSCTL_FAN1 1101 /* Rotations/min */ +#define MAXI_SYSCTL_FAN2 1102 /* Rotations/min */ +#define MAXI_SYSCTL_FAN3 1103 /* Rotations/min */ +#define MAXI_SYSCTL_FAN4 1104 /* Rotations/min */ +#define MAXI_SYSCTL_TEMP1 1201 /* Degrees Celsius */ +#define MAXI_SYSCTL_TEMP2 1202 /* Degrees Celsius */ +#define MAXI_SYSCTL_TEMP3 1203 /* Degrees Celsius */ +#define MAXI_SYSCTL_TEMP4 1204 /* Degrees Celsius */ +#define MAXI_SYSCTL_TEMP5 1205 /* Degrees Celsius */ +#define MAXI_SYSCTL_TEMP6 1206 /* Degrees Celsius */ +#define MAXI_SYSCTL_PLL 1301 /* MHz */ +#define MAXI_SYSCTL_VID1 1401 /* Volts / 6.337, for nba just Volts */ +#define MAXI_SYSCTL_VID2 1402 /* Volts */ +#define MAXI_SYSCTL_VID3 1403 /* Volts */ +#define MAXI_SYSCTL_VID4 1404 /* Volts */ +#define MAXI_SYSCTL_VID5 1405 /* Volts */ +#define MAXI_SYSCTL_LCD1 1501 /* Line 1 of LCD */ +#define MAXI_SYSCTL_LCD2 1502 /* Line 2 of LCD */ +#define MAXI_SYSCTL_LCD3 1503 /* Line 3 of LCD */ +#define MAXI_SYSCTL_LCD4 1504 /* Line 4 of LCD */ +#define MAXI_SYSCTL_ALARMS 2001 /* Bitvector (see below) */ + +#define MAXI_ALARM_VID4 0x0001 +#define MAXI_ALARM_TEMP2 0x0002 +#define MAXI_ALARM_VID1 0x0004 +#define MAXI_ALARM_VID2 0x0008 +#define MAXI_ALARM_VID3 0x0010 +#define MAXI_ALARM_PLL 0x0080 +#define MAXI_ALARM_TEMP4 0x0100 +#define MAXI_ALARM_TEMP5 0x0200 +#define MAXI_ALARM_FAN1 0x1000 +#define MAXI_ALARM_FAN2 0x2000 +#define MAXI_ALARM_FAN3 0x4000 + +#define MAXI_ALARM_FAN 0x0100 /* To be used with MaxiLife'99 */ +#define MAXI_ALARM_VID 0x0200 /* The MSB specifies which sensor */ +#define MAXI_ALARM_TEMP 0x0400 /* in the alarm group failed, i.e.: */ +#define MAXI_ALARM_VADD 0x0800 /* 0x0402 = TEMP2 failed = CPU2 temp */ + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define MIC74_SYSCTL_REG0 1000 +#define MIC74_SYSCTL_REG1 1001 +#define MIC74_SYSCTL_REG2 1002 +#define MIC74_SYSCTL_REG3 1003 +#define MIC74_SYSCTL_REG4 1004 +#define MIC74_SYSCTL_REG5 1005 +#define MIC74_SYSCTL_REG6 1006 +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define MTP008_SYSCTL_IN0 1000 /* Volts * 100 */ +#define MTP008_SYSCTL_IN1 1001 +#define MTP008_SYSCTL_IN2 1002 +#define MTP008_SYSCTL_IN3 1003 +#define MTP008_SYSCTL_IN4 1004 +#define MTP008_SYSCTL_IN5 1005 +#define MTP008_SYSCTL_IN6 1006 +#define MTP008_SYSCTL_FAN1 1101 /* Rotations/min */ +#define MTP008_SYSCTL_FAN2 1102 +#define MTP008_SYSCTL_FAN3 1103 +#define MTP008_SYSCTL_TEMP1 1200 /* Degrees Celsius * 10 */ +#define MTP008_SYSCTL_TEMP2 1201 /* Degrees Celsius * 10 */ +#define MTP008_SYSCTL_TEMP3 1202 /* Degrees Celsius * 10 */ +#define MTP008_SYSCTL_VID 1300 /* Volts * 100 */ +#define MTP008_SYSCTL_PWM1 1401 +#define MTP008_SYSCTL_PWM2 1402 +#define MTP008_SYSCTL_PWM3 1403 +#define MTP008_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */ +#define MTP008_SYSCTL_SENS2 1502 +#define MTP008_SYSCTL_SENS3 1503 +#define MTP008_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define MTP008_SYSCTL_ALARMS 2001 /* bitvector */ +#define MTP008_SYSCTL_BEEP 2002 /* bitvector */ + +#define MTP008_ALARM_IN0 0x0001 +#define MTP008_ALARM_IN1 0x0002 +#define MTP008_ALARM_IN2 0x0004 +#define MTP008_ALARM_IN3 0x0008 +#define MTP008_ALARM_IN4 0x0100 +#define MTP008_ALARM_IN5 0x0200 +#define MTP008_ALARM_IN6 0x0400 +#define MTP008_ALARM_FAN1 0x0040 +#define MTP008_ALARM_FAN2 0x0080 +#define MTP008_ALARM_FAN3 0x0800 +#define MTP008_ALARM_TEMP1 0x0010 +#define MTP008_ALARM_TEMP2 0x0100 +#define MTP008_ALARM_TEMP3 0x0200 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define PC87365_SYSCTL_ALARMS 100 /* bit field */ + +#define PC87360_SYSCTL_FAN1 1101 /* Rotations/min */ +#define PC87360_SYSCTL_FAN2 1102 +#define PC87360_SYSCTL_FAN3 1103 /* not for PC87360/PC87363 */ +#define PC87360_SYSCTL_FAN_DIV 1201 /* 1, 2, 4 or 8 */ +#define PC87360_SYSCTL_FAN1_STATUS 1301 /* bit field */ +#define PC87360_SYSCTL_FAN2_STATUS 1302 +#define PC87360_SYSCTL_FAN3_STATUS 1303 /* not for PC87360/PC87363 */ +#define PC87360_SYSCTL_PWM1 1401 /* 0-255 */ +#define PC87360_SYSCTL_PWM2 1402 +#define PC87360_SYSCTL_PWM3 1403 /* not for PC87360/PC87363 */ + +#define PC87360_STATUS_FAN_READY 0x01 +#define PC87360_STATUS_FAN_LOW 0x02 +#define PC87360_STATUS_FAN_OVERFLOW 0x04 + +#define PC87365_SYSCTL_IN0 2100 /* mV */ +#define PC87365_SYSCTL_IN1 2101 +#define PC87365_SYSCTL_IN2 2102 +#define PC87365_SYSCTL_IN3 2103 +#define PC87365_SYSCTL_IN4 2104 +#define PC87365_SYSCTL_IN5 2105 +#define PC87365_SYSCTL_IN6 2106 +#define PC87365_SYSCTL_IN7 2107 +#define PC87365_SYSCTL_IN8 2108 +#define PC87365_SYSCTL_IN9 2109 +#define PC87365_SYSCTL_IN10 2110 +#define PC87365_SYSCTL_TEMP4 2111 /* not for PC87365 */ +#define PC87365_SYSCTL_TEMP5 2112 /* not for PC87365 */ +#define PC87365_SYSCTL_TEMP6 2113 /* not for PC87365 */ +#define PC87365_SYSCTL_IN0_STATUS 2300 /* bit field */ +#define PC87365_SYSCTL_IN1_STATUS 2301 +#define PC87365_SYSCTL_IN2_STATUS 2302 +#define PC87365_SYSCTL_IN3_STATUS 2303 +#define PC87365_SYSCTL_IN4_STATUS 2304 +#define PC87365_SYSCTL_IN5_STATUS 2305 +#define PC87365_SYSCTL_IN6_STATUS 2306 +#define PC87365_SYSCTL_IN7_STATUS 2307 +#define PC87365_SYSCTL_IN8_STATUS 2308 +#define PC87365_SYSCTL_IN9_STATUS 2309 +#define PC87365_SYSCTL_IN10_STATUS 2310 +#define PC87365_SYSCTL_TEMP4_STATUS 2311 /* not for PC87365 */ +#define PC87365_SYSCTL_TEMP5_STATUS 2312 /* not for PC87365 */ +#define PC87365_SYSCTL_TEMP6_STATUS 2313 /* not for PC87365 */ + +#define PC87365_SYSCTL_VID 2400 +#define PC87365_SYSCTL_VRM 2401 + +#define PC87365_STATUS_IN_MIN 0x02 +#define PC87365_STATUS_IN_MAX 0x04 + +#define PC87365_SYSCTL_TEMP1 3101 /* degrees Celsius */ +#define PC87365_SYSCTL_TEMP2 3102 +#define PC87365_SYSCTL_TEMP3 3103 /* not for PC87365 */ +#define PC87365_SYSCTL_TEMP1_STATUS 3301 /* bit field */ +#define PC87365_SYSCTL_TEMP2_STATUS 3302 +#define PC87365_SYSCTL_TEMP3_STATUS 3303 /* not for PC87365 */ + +#define PC87365_STATUS_TEMP_MIN 0x02 +#define PC87365_STATUS_TEMP_MAX 0x04 +#define PC87365_STATUS_TEMP_CRIT 0x08 +#define PC87365_STATUS_TEMP_OPEN 0x40 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define PCA9540_SYSCTL_CHANNEL 1000 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define PCF8574_SYSCTL_READ 1000 +#define PCF8574_SYSCTL_WRITE 1001 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define PCF8591_SYSCTL_AIN_CONF 1000 /* Analog input configuration */ +#define PCF8591_SYSCTL_CH0 1001 /* Input channel 1 */ +#define PCF8591_SYSCTL_CH1 1002 /* Input channel 2 */ +#define PCF8591_SYSCTL_CH2 1003 /* Input channel 3 */ +#define PCF8591_SYSCTL_CH3 1004 /* Input channel 4 */ +#define PCF8591_SYSCTL_AOUT_ENABLE 1005 /* Analog output enable flag */ +#define PCF8591_SYSCTL_AOUT 1006 /* Analog output */ +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define SAA1064_SYSCTL_BRIGHT 1000 /* Brightness, 0-7 */ +#define SAA1064_SYSCTL_TEST 1001 /* Testmode (on = all digits lit) */ +#define SAA1064_SYSCTL_DISP 1005 /* four eight bit values */ +#define SAA1064_SYSCTL_REFRESH 1006 /* refresh digits in case of powerloss */ + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define SIS5595_SYSCTL_IN0 1000 /* Volts * 100 */ +#define SIS5595_SYSCTL_IN1 1001 +#define SIS5595_SYSCTL_IN2 1002 +#define SIS5595_SYSCTL_IN3 1003 +#define SIS5595_SYSCTL_IN4 1004 +#define SIS5595_SYSCTL_FAN1 1101 /* Rotations/min */ +#define SIS5595_SYSCTL_FAN2 1102 +#define SIS5595_SYSCTL_TEMP 1200 /* Degrees Celsius * 10 */ +#define SIS5595_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define SIS5595_SYSCTL_ALARMS 2001 /* bitvector */ + +#define SIS5595_ALARM_IN0 0x01 +#define SIS5595_ALARM_IN1 0x02 +#define SIS5595_ALARM_IN2 0x04 +#define SIS5595_ALARM_IN3 0x08 +#define SIS5595_ALARM_BTI 0x20 +#define SIS5595_ALARM_FAN1 0x40 +#define SIS5595_ALARM_FAN2 0x80 +#define SIS5595_ALARM_IN4 0x8000 +#define SIS5595_ALARM_TEMP 0x8000 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +/* Status Register Bits */ +/* * * * * * Alarm Bits * * * * */ +#define SMARTBATT_OVER_CHARGED_ALARM 0x8000 +#define SMARTBATT_TERMINATE_CHARGE_ALARM 0x4000 +#define SMARTBATT_OVER_TEMP_ALARM 0x1000 +#define SMARTBATT_TERMINATE_DISCHARGE_ALARM 0x0800 +#define SMARTBATT_REMAINING_CAPACITY_ALARM 0x0200 +#define SMARTBATT_REMAINING_TIME_ALARM 0x0100 +/* * * * * * Status Bits * * * * */ +#define SMARTBATT_INITIALIZED 0x0080 +#define SMARTBATT_DISCHARGING 0x0040 +#define SMARTBATT_FULLY_CHARGED 0x0020 +#define SMARTBATT_FULLY_DISCHARGED 0x0010 +/* * * * * * Error Bits * * * * */ +#define SMARTBATT_OK 0x0000 +#define SMARTBATT_BUSY 0x0001 +#define SMARTBATT_RESERVED_COMMAND 0x0002 +#define SMARTBATT_UNSUPPORTED_COMMAND 0x0003 +#define SMARTBATT_ACCESS_DENIED 0x0004 +#define SMARTBATT_OVER_UNDERFLOW 0x0005 +#define SMARTBATT_BAD_SIZE 0x0006 +#define SMARTBATT_UNKNOWN_ERROR 0x0007 + +#define SMARTBATT_ALARM (SMARTBATT_OVER_CHARGED_ALARM \ + | SMARTBATT_TERMINATE_CHARGE_ALARM | SMARTBATT_OVER_TEMP_ALARM \ + | SMARTBATT_TERMINATE_DISCHARGE_ALARM \ + | SMARTBATT_REMAINING_CAPACITY_ALARM \ + | SMARTBATT_REMAINING_TIME_ALARM) + +#define SMARTBATT_STATUS (SMARTBATT_INITIALIZED | SMARTBATT_DISCHARGING \ + | SMARTBATT_FULLY_CHARGED | SMARTBATT_FULLY_DISCHARGED ) + +#define SMARTBATT_ERROR (SMARTBATT_BUSY | SMARTBATT_RESERVED_COMMAND \ + | SMARTBATT_UNSUPPORTED_COMMAND | SMARTBATT_ACCESS_DENIED \ + | SMARTBATT_OVER_UNDERFLOW | SMARTBATT_BAD_SIZE\ + | SMARTBATT_UNKNOWN_ERROR) + + +#define SMARTBATT_SYSCTL_I 1001 +#define SMARTBATT_SYSCTL_V 1002 +#define SMARTBATT_SYSCTL_TEMP 1003 +#define SMARTBATT_SYSCTL_TIME 1004 +#define SMARTBATT_SYSCTL_ALARMS 1005 +#define SMARTBATT_SYSCTL_STATUS 1006 +#define SMARTBATT_SYSCTL_ERROR 1007 +#define SMARTBATT_SYSCTL_CHARGE 1008 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define ARP_SYSCTL1 1000 +#define ARP_SYSCTL2 1001 +#define ARP_SYSCTL3 1002 +#define ARP_SYSCTL4 1003 +#define ARP_SYSCTL5 1004 +#define ARP_SYSCTL6 1005 +#define ARP_SYSCTL7 1006 +#define ARP_SYSCTL8 1007 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define SMSC47M1_SYSCTL_FAN1 1101 /* Rotations/min */ +#define SMSC47M1_SYSCTL_FAN2 1102 +#define SMSC47M1_SYSCTL_FAN3 1103 +#define SMSC47M1_SYSCTL_PWM1 1401 +#define SMSC47M1_SYSCTL_PWM2 1402 +#define SMSC47M1_SYSCTL_PWM3 1403 +#define SMSC47M1_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define SMSC47M1_SYSCTL_ALARMS 2004 /* bitvector */ + +#define SMSC47M1_ALARM_FAN1 0x0001 +#define SMSC47M1_ALARM_FAN2 0x0002 +#define SMSC47M1_ALARM_FAN3 0x0004 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define THMC50_SYSCTL_TEMP 1200 /* Degrees Celsius */ +#define THMC50_SYSCTL_REMOTE_TEMP 1201 /* Degrees Celsius */ +#define THMC50_SYSCTL_INTER 1202 +#define THMC50_SYSCTL_INTER_MASK 1203 +#define THMC50_SYSCTL_DIE_CODE 1204 +#define THMC50_SYSCTL_ANALOG_OUT 1205 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define VIA686A_SYSCTL_IN0 1000 +#define VIA686A_SYSCTL_IN1 1001 +#define VIA686A_SYSCTL_IN2 1002 +#define VIA686A_SYSCTL_IN3 1003 +#define VIA686A_SYSCTL_IN4 1004 +#define VIA686A_SYSCTL_FAN1 1101 +#define VIA686A_SYSCTL_FAN2 1102 +#define VIA686A_SYSCTL_TEMP 1200 +#define VIA686A_SYSCTL_TEMP2 1201 +#define VIA686A_SYSCTL_TEMP3 1202 +#define VIA686A_SYSCTL_FAN_DIV 2000 +#define VIA686A_SYSCTL_ALARMS 2001 + +#define VIA686A_ALARM_IN0 0x01 +#define VIA686A_ALARM_IN1 0x02 +#define VIA686A_ALARM_IN2 0x04 +#define VIA686A_ALARM_IN3 0x08 +#define VIA686A_ALARM_TEMP 0x10 +#define VIA686A_ALARM_FAN1 0x40 +#define VIA686A_ALARM_FAN2 0x80 +#define VIA686A_ALARM_IN4 0x100 +#define VIA686A_ALARM_TEMP2 0x800 +#define VIA686A_ALARM_CHAS 0x1000 +#define VIA686A_ALARM_TEMP3 0x8000 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define VT1211_SYSCTL_IN0 1000 +#define VT1211_SYSCTL_IN1 1001 +#define VT1211_SYSCTL_IN2 1002 +#define VT1211_SYSCTL_IN3 1003 +#define VT1211_SYSCTL_IN4 1004 +#define VT1211_SYSCTL_IN5 1005 +#define VT1211_SYSCTL_FAN1 1101 +#define VT1211_SYSCTL_FAN2 1102 +#define VT1211_SYSCTL_TEMP1 1200 +#define VT1211_SYSCTL_TEMP2 1201 +#define VT1211_SYSCTL_TEMP3 1202 +#define VT1211_SYSCTL_TEMP4 1203 +#define VT1211_SYSCTL_TEMP5 1204 +#define VT1211_SYSCTL_TEMP6 1205 +#define VT1211_SYSCTL_TEMP7 1206 +#define VT1211_SYSCTL_VID 1300 +#define VT1211_SYSCTL_PWM1 1401 +#define VT1211_SYSCTL_PWM2 1402 +#define VT1211_SYSCTL_VRM 1600 +#define VT1211_SYSCTL_UCH 1700 +#define VT1211_SYSCTL_FAN_DIV 2000 +#define VT1211_SYSCTL_ALARMS 2001 + +#define VT1211_ALARM_IN1 0x01 +#define VT1211_ALARM_IN2 0x02 +#define VT1211_ALARM_IN5 0x04 +#define VT1211_ALARM_IN3 0x08 +#define VT1211_ALARM_TEMP1 0x10 +#define VT1211_ALARM_FAN1 0x40 +#define VT1211_ALARM_FAN2 0x80 +#define VT1211_ALARM_IN4 0x100 +#define VT1211_ALARM_TEMP3 0x800 +#define VT1211_ALARM_CHAS 0x1000 +#define VT1211_ALARM_TEMP2 0x8000 +/* duplicates */ +#define VT1211_ALARM_IN0 VT1211_ALARM_TEMP3 +#define VT1211_ALARM_TEMP4 VT1211_ALARM_IN1 +#define VT1211_ALARM_TEMP5 VT1211_ALARM_IN2 +#define VT1211_ALARM_TEMP6 VT1211_ALARM_IN3 +#define VT1211_ALARM_TEMP7 VT1211_ALARM_IN4 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ +#define VT8231_SYSCTL_IN0 1000 +#define VT8231_SYSCTL_IN1 1001 +#define VT8231_SYSCTL_IN2 1002 +#define VT8231_SYSCTL_IN3 1003 +#define VT8231_SYSCTL_IN4 1004 +#define VT8231_SYSCTL_IN5 1005 +#define VT8231_SYSCTL_FAN1 1101 +#define VT8231_SYSCTL_FAN2 1102 +#define VT8231_SYSCTL_TEMP 1200 +#define VT8231_SYSCTL_TEMP2 1201 +#define VT8231_SYSCTL_TEMP3 1202 +#define VT8231_SYSCTL_TEMP4 1203 +#define VT8231_SYSCTL_TEMP5 1204 +#define VT8231_SYSCTL_TEMP6 1205 +#define VT8231_SYSCTL_VID 1300 +#define VT8231_SYSCTL_PWM1 1401 +#define VT8231_SYSCTL_PWM2 1402 +#define VT8231_SYSCTL_VRM 1600 +#define VT8231_SYSCTL_UCH 1700 +#define VT8231_SYSCTL_FAN_DIV 2000 +#define VT8231_SYSCTL_ALARMS 2001 + +#define VT8231_ALARM_IN1 0x01 +#define VT8231_ALARM_IN2 0x02 +#define VT8231_ALARM_IN5 0x04 +#define VT8231_ALARM_IN3 0x08 +#define VT8231_ALARM_TEMP 0x10 +#define VT8231_ALARM_FAN1 0x40 +#define VT8231_ALARM_FAN2 0x80 +#define VT8231_ALARM_IN4 0x100 +#define VT8231_ALARM_TEMP2 0x800 +#define VT8231_ALARM_CHAS 0x1000 +/* duplicates */ +#define VT8231_ALARM_IN0 VT8231_ALARM_TEMP2 +#define VT8231_ALARM_TEMP3 VT8231_ALARM_IN1 +#define VT8231_ALARM_TEMP4 VT8231_ALARM_IN2 +#define VT8231_ALARM_TEMP5 VT8231_ALARM_IN3 +#define VT8231_ALARM_TEMP6 VT8231_ALARM_IN4 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define W83781D_SYSCTL_IN0 1000 /* Volts * 100 */ +#define W83781D_SYSCTL_IN1 1001 +#define W83781D_SYSCTL_IN2 1002 +#define W83781D_SYSCTL_IN3 1003 +#define W83781D_SYSCTL_IN4 1004 +#define W83781D_SYSCTL_IN5 1005 +#define W83781D_SYSCTL_IN6 1006 +#define W83781D_SYSCTL_IN7 1007 +#define W83781D_SYSCTL_IN8 1008 +#define W83781D_SYSCTL_FAN1 1101 /* Rotations/min */ +#define W83781D_SYSCTL_FAN2 1102 +#define W83781D_SYSCTL_FAN3 1103 +#define W83781D_SYSCTL_TEMP1 1200 /* Degrees Celsius * 10 */ +#define W83781D_SYSCTL_TEMP2 1201 /* Degrees Celsius * 10 */ +#define W83781D_SYSCTL_TEMP3 1202 /* Degrees Celsius * 10 */ +#define W83781D_SYSCTL_VID 1300 /* Volts * 1000 */ +#define W83781D_SYSCTL_VRM 1301 +#define W83781D_SYSCTL_PWM1 1401 +#define W83781D_SYSCTL_PWM2 1402 +#define W83781D_SYSCTL_PWM3 1403 +#define W83781D_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */ +#define W83781D_SYSCTL_SENS2 1502 +#define W83781D_SYSCTL_SENS3 1503 +#define W83781D_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define W83781D_SYSCTL_ALARMS 2001 /* bitvector */ +#define W83781D_SYSCTL_BEEP 2002 /* bitvector */ + +#define W83781D_ALARM_IN0 0x0001 +#define W83781D_ALARM_IN1 0x0002 +#define W83781D_ALARM_IN2 0x0004 +#define W83781D_ALARM_IN3 0x0008 +#define W83781D_ALARM_IN4 0x0100 +#define W83781D_ALARM_IN5 0x0200 +#define W83781D_ALARM_IN6 0x0400 +#define W83782D_ALARM_IN7 0x10000 +#define W83782D_ALARM_IN8 0x20000 +#define W83781D_ALARM_FAN1 0x0040 +#define W83781D_ALARM_FAN2 0x0080 +#define W83781D_ALARM_FAN3 0x0800 +#define W83781D_ALARM_TEMP1 0x0010 +#define W83781D_ALARM_TEMP23 0x0020 /* 781D only */ +#define W83781D_ALARM_TEMP2 0x0020 /* 782D/783S */ +#define W83781D_ALARM_TEMP3 0x2000 /* 782D only */ +#define W83781D_ALARM_CHAS 0x1000 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define W83781D_SYSCTL_IN0 1000 /* Volts * 100 */ +#define W83781D_SYSCTL_IN1 1001 +#define W83781D_SYSCTL_IN2 1002 +#define W83781D_SYSCTL_IN3 1003 +#define W83781D_SYSCTL_IN4 1004 +#define W83781D_SYSCTL_IN5 1005 +#define W83781D_SYSCTL_IN6 1006 +#define W83781D_SYSCTL_IN7 1007 +#define W83781D_SYSCTL_IN8 1008 +#define W83781D_SYSCTL_IN9 1009 +#define W83781D_SYSCTL_FAN1 1101 /* Rotations/min */ +#define W83781D_SYSCTL_FAN2 1102 +#define W83781D_SYSCTL_FAN3 1103 +#define W83781D_SYSCTL_FAN4 1104 +#define W83781D_SYSCTL_FAN5 1105 + +#define W83781D_SYSCTL_TEMP1 1200 /* Degrees Celsius * 10 */ +#define W83781D_SYSCTL_TEMP2 1201 /* Degrees Celsius * 10 */ +#define W83781D_SYSCTL_TEMP3 1202 /* Degrees Celsius * 10 */ +#define W83781D_SYSCTL_VID 1300 /* Volts * 1000 */ +#define W83781D_SYSCTL_VRM 1301 +#define W83781D_SYSCTL_PWM1 1401 +#define W83781D_SYSCTL_PWM2 1402 +#define W83781D_SYSCTL_PWM3 1403 +#define W83781D_SYSCTL_PWM4 1404 +#define W83781D_SYSCTL_SENS1 1501 /* 1, 2, or Beta (3000-5000) */ +#define W83781D_SYSCTL_SENS2 1502 +#define W83781D_SYSCTL_SENS3 1503 +#define W83781D_SYSCTL_RT1 1601 /* 32-entry table */ +#define W83781D_SYSCTL_RT2 1602 /* 32-entry table */ +#define W83781D_SYSCTL_RT3 1603 /* 32-entry table */ +#define W83781D_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define W83781D_SYSCTL_ALARMS 2001 /* bitvector */ +#define W83781D_SYSCTL_BEEP 2002 /* bitvector */ + +#define W83781D_ALARM_IN0 0x0001 +#define W83781D_ALARM_IN1 0x0002 +#define W83781D_ALARM_IN2 0x0004 +#define W83781D_ALARM_IN3 0x0008 +#define W83781D_ALARM_IN4 0x0100 +#define W83781D_ALARM_IN5 0x0200 +#define W83781D_ALARM_IN6 0x0400 +#define W83782D_ALARM_IN7 0x10000 +#define W83782D_ALARM_IN8 0x20000 +#define W83791D_ALARM_IN7 0x080000 /* 791D only */ +#define W83791D_ALARM_IN8 0x100000 /* 791D only */ +#define W83791D_ALARM_IN9 0x004000 /* 791D only */ +#define W83781D_ALARM_FAN1 0x0040 +#define W83781D_ALARM_FAN2 0x0080 +#define W83781D_ALARM_FAN3 0x0800 +#define W83791D_ALARM_FAN4 0x200000 /* 791D only */ +#define W83791D_ALARM_FAN5 0x400000 /* 791D only */ +#define W83781D_ALARM_TEMP1 0x0010 +#define W83781D_ALARM_TEMP23 0x0020 /* 781D only */ +#define W83781D_ALARM_TEMP2 0x0020 /* 782D/783S/791D */ +#define W83781D_ALARM_TEMP3 0x2000 /* 782D/791D */ +#define W83781D_ALARM_CHAS 0x1000 /* 782D/791D */ + +#define W83791D_BEEP_IN1 0x002000 /* 791D only */ +#define W83791D_BEEP_IN7 0x010000 /* 791D only */ +#define W83791D_BEEP_IN8 0x020000 /* 791D only */ +#define W83791D_BEEP_TEMP3 0x000002 /* 791D only */ + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define W83792D_SYSCTL_IN0 1000 +#define W83792D_SYSCTL_IN1 1001 +#define W83792D_SYSCTL_IN2 1002 +#define W83792D_SYSCTL_IN3 1003 +#define W83792D_SYSCTL_IN4 1004 +#define W83792D_SYSCTL_IN5 1005 +#define W83792D_SYSCTL_IN6 1006 +#define W83792D_SYSCTL_IN7 1007 +#define W83792D_SYSCTL_IN8 1008 +#define W83792D_SYSCTL_FAN1 1101 +#define W83792D_SYSCTL_FAN2 1102 +#define W83792D_SYSCTL_FAN3 1103 +#define W83792D_SYSCTL_FAN4 1104 +#define W83792D_SYSCTL_FAN5 1105 +#define W83792D_SYSCTL_FAN6 1106 +#define W83792D_SYSCTL_FAN7 1107 + +#define W83792D_SYSCTL_TEMP1 1200 +#define W83792D_SYSCTL_TEMP2 1201 +#define W83792D_SYSCTL_TEMP3 1202 +/*#define W83792D_SYSCTL_VID 1300 +#define W83792D_SYSCTL_VRM 1301*/ +#define W83792D_SYSCTL_PWM_FLAG 1400 +#define W83792D_SYSCTL_PWM1 1401 +#define W83792D_SYSCTL_PWM2 1402 +#define W83792D_SYSCTL_PWM3 1403 +#define W83792D_SYSCTL_FAN_CFG 1500 /* control Fan Mode */ +#define W83792D_SYSCTL_FAN_DIV 1501 +#define W83792D_SYSCTL_CHASSIS 1502 /* control Case Open */ +#define W83792D_SYSCTL_ALARMS 1503 + +#define W83792D_SYSCTL_THERMAL_CRUISE 1600 /* Smart Fan I: target value */ +#define W83792D_SYSCTL_FAN_TOLERANCE 1601 /* Smart Fan I/II: tolerance */ +#define W83792D_SYSCTL_SF2_POINTS_FAN1 1602 /* Smart Fan II: Fan1 points */ +#define W83792D_SYSCTL_SF2_POINTS_FAN2 1603 /* Smart Fan II: Fan2 points */ +#define W83792D_SYSCTL_SF2_POINTS_FAN3 1604 /* Smart Fan II: Fan3 points */ +#define W83792D_SYSCTL_SF2_LEVELS_FAN1 1605 /* Smart Fan II: Fan1 levels */ +#define W83792D_SYSCTL_SF2_LEVELS_FAN2 1606 /* Smart Fan II: Fan2 levels */ +#define W83792D_SYSCTL_SF2_LEVELS_FAN3 1607 /* Smart Fan II: Fan3 levels */ + +#define W83792D_ALARM_IN0 0x0001 +#define W83792D_ALARM_IN1 0x0002 +#define W83792D_ALARM_IN2 0x0100 +#define W83792D_ALARM_IN3 0x0200 +#define W83792D_ALARM_IN4 0x0400 +#define W83792D_ALARM_IN5 0x0800 +#define W83792D_ALARM_IN6 0x1000 +#define W83792D_ALARM_IN7 0x80000 +#define W83792D_ALARM_IN8 0x100000 +#define W83792D_ALARM_TEMP1 0x0004 +#define W83792D_ALARM_TEMP2 0x0008 +#define W83792D_ALARM_TEMP3 0x0010 +#define W83792D_ALARM_FAN1 0x0020 +#define W83792D_ALARM_FAN2 0x0040 +#define W83792D_ALARM_FAN3 0x0080 +#define W83792D_ALARM_FAN4 0x200000 +#define W83792D_ALARM_FAN5 0x400000 +#define W83792D_ALARM_FAN6 0x800000 +#define W83792D_ALARM_FAN7 0x8000 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define W83L785TS_SYSCTL_TEMP 1200 + +/* -- SENSORS SYSCTL END -- */ +/* -- SENSORS SYSCTL START -- */ + +#define XEONTEMP_SYSCTL_REMOTE_TEMP 1201 +#define XEONTEMP_SYSCTL_ALARMS 1203 + +#define XEONTEMP_ALARM_RTEMP_HIGH 0x10 +#define XEONTEMP_ALARM_RTEMP_LOW 0x08 +#define XEONTEMP_ALARM_RTEMP_NA 0x04 + +/* -- SENSORS SYSCTL END -- */ +#endif diff --git a/kernel/include/sensors.h.template b/kernel/include/sensors.h.template deleted file mode 100644 index 8a60a74b..00000000 --- a/kernel/include/sensors.h.template +++ /dev/null @@ -1,55 +0,0 @@ -/* - sensors.h - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - --- THIS FILE IS AUTOGENERATED DO NOT EDIT -- -*/ - -#ifndef LIB_SENSORS_H -#define LIB_SENSORS_H - -/* This file is intended to be included from userland utilities only. - * - * Individual drivers define their own SYSCTL and ALARM values in - * the driver itself surrounded by the following 'trigger' lines: - * - * -- SENSORS SYSCTL START -- - * -- SENSORS SYSCTL END -- - */ - - -/* From linux/i2c-proc.h */ - -/* Sysctl IDs */ -#ifdef DEV_HWMON -#define DEV_SENSORS DEV_HWMON -#else /* ndef DEV_HWMOM */ -#define DEV_SENSORS 2 /* The id of the lm_sensors directory within the - dev table */ -#endif /* def DEV_HWMON */ - -/* The maximum length of the prefix */ -#define SENSORS_PREFIX_MAX 20 - -#define SENSORS_CHIPS 1 -struct i2c_chips_data { - int sysctl_id; - char name[SENSORS_PREFIX_MAX + 13]; -}; - - diff --git a/kernel/include/sensors_compat.h b/kernel/include/sensors_compat.h deleted file mode 100644 index ccde2b82..00000000 --- a/kernel/include/sensors_compat.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Stolen from kernel 2.5.69 - * device.h - generic, centralized driver model - * To make it easier to backport from 2.5 - * - * Copyright (c) 2001-2003 Patrick Mochel - * - */ - -#ifndef _SENSORS_COMPAT_H_ -#define _SENSORS_COMPAT_H_ - -#include - -/* debugging and troubleshooting/diagnostic helpers. */ -#define dev_printk(level, dev, format, arg...) \ - printk(level "%s: " format , (dev)->name , ## arg) - -#ifdef DEBUG -#define dev_dbg(dev, format, arg...) \ - dev_printk(KERN_DEBUG , dev , format , ## arg) -#else -#define dev_dbg(dev, format, arg...) do {} while (0) -#endif - -#define dev_err(dev, format, arg...) \ - dev_printk(KERN_ERR , dev , format , ## arg) -#define dev_info(dev, format, arg...) \ - dev_printk(KERN_INFO , dev , format , ## arg) -#define dev_warn(dev, format, arg...) \ - dev_printk(KERN_WARNING , dev , format , ## arg) - - -/* The part below, taken from linux/init.h, is required for compatibility with - kernels 2.4.16 and older, which don't know about __devexit_p. */ - -/* Functions marked as __devexit may be discarded at kernel link time, depending - on config options. Newer versions of binutils detect references from - retained sections to discarded sections and flag an error. Pointers to - __devexit functions must use __devexit_p(function_name), the wrapper will - insert either the function_name or NULL, depending on the config options. - */ -#ifndef __devexit_p -#if defined(MODULE) || defined(CONFIG_HOTPLUG) -#define __devexit_p(x) x -#else -#define __devexit_p(x) NULL -#endif -#endif /* __devexit_p */ - -#endif /* _SENSORS_COMPAT_H_ */ diff --git a/kernel/include/sensors_vid.h b/kernel/include/sensors_vid.h deleted file mode 100644 index 81b36b66..00000000 --- a/kernel/include/sensors_vid.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - sensors_vid.h - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 2002-2004 Mark D. Studebaker - With assistance from Trent Piepho - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - This file contains common code for decoding VID pins. - This file is #included in various sensor chip drivers. - As the user is unlikely to load more than one driver which - includes this code we don't worry about the wasted space. - References: VRM x.y DC-DC Converter Design Guidelines, - VRD 10.0 Design Guide, - available at http://developer.intel.com -*/ - -/* - AMD Opteron processors don't follow the Intel VRM spec. - I'm going to "make up" 2.4 as the VRM spec for the Opterons. - No good reason just a mnemonic for the 24x Opteron processor - series - - Opteron VID encoding is: - - 00000 = 1.550 V - 00001 = 1.525 V - . . . . - 11110 = 0.800 V - 11111 = 0.000 V (off) - */ - -/* - Legal val values 00 - 1F except for VRD 10.0, 0x00-0x3f. - vrm is the Intel VRM document version. - Note: vrm version is scaled by 10 and the return value is scaled by 1000 - to avoid floating point in the kernel. -*/ - -static inline int vid_from_reg(int val, int vrm) -{ - int vid; - - switch(vrm) { - - case 100: /* VRD 10.0 */ - val &= 0x3f; - if((val & 0x1f) == 0x1f) - return 0; - if((val & 0x1f) <= 0x09 || val == 0x0a) - vid = 10875 - (val & 0x1f) * 250; - else - vid = 18625 - (val & 0x1f) * 250; - if(val & 0x20) - vid -= 125; - vid /= 10; /* only return 3 dec. places for now */ - return vid; - - case 24: /* Opteron processor */ - val &= 0x1f; - return(val == 0x1f ? 0 : 1550 - val * 25); - - case 91: /* VRM 9.1 */ - case 90: /* VRM 9.0 */ - val &= 0x1f; - return(val == 0x1f ? 0 : - 1850 - val * 25); - - case 85: /* VRM 8.5 */ - val &= 0x1f; - return((val & 0x10 ? 25 : 0) + - ((val & 0x0f) > 0x04 ? 2050 : 1250) - - ((val & 0x0f) * 50)); - - case 84: /* VRM 8.4 */ - val &= 0x0f; - /* fall through */ - default: /* VRM 8.2 */ - val &= 0x1f; - return(val == 0x1f ? 0 : - val & 0x10 ? 5100 - (val) * 100 : - 2050 - (val) * 50); - } -} diff --git a/kernel/sensors.c b/kernel/sensors.c deleted file mode 100644 index 6b0e7014..00000000 --- a/kernel/sensors.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - sensors.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998, 1999 Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - diff --git a/lm_sensors.lsm b/lm_sensors.lsm index 96b1f3cb..f197b53a 100644 --- a/lm_sensors.lsm +++ b/lm_sensors.lsm @@ -3,14 +3,11 @@ Title: lm_sensors Version: 2.10.3 Entered-date: 29DEC98 Description: Hardware health monitoring package for Linux. It consists of - kernel modules to access sensor chips and SMBus hardware, - of a library to allow applications to read this data more + a library to allow applications to read sensors data more easily, and of an example program to pretty print this data. - LM78, LM79, LM80, W83781D and GL518SM sensor chips are - supported, among others. Version 2 is a complete non-compatible modular rewrite of this package. -Keywords: kernel module SMBus sensors LM78 health +Keywords: sensors health Author: frodol@dds.nl (Frodo Looijaard) phil@netroedge.com (Philip Edelbrock) and other great contributors