Merge branch 'release' of git://lm-sensors.org/kernel/mhoffman/hwmon-2.6

* 'release' of git://lm-sensors.org/kernel/mhoffman/hwmon-2.6: (59 commits)
  hwmon: (lm80) Add individual alarm files
  hwmon: (lm80) De-macro the sysfs callbacks
  hwmon: (lm80) Various cleanups
  hwmon: (w83627hf) Refactor beep enable handling
  hwmon: (w83627hf) Add individual alarm and beep files
  hwmon: (w83627hf) Enable VBAT monitoring
  hwmon: (w83627ehf) The W83627DHG has 8 VID pins
  hwmon: (asb100) Add individual alarm files
  hwmon: (asb100) De-macro the sysfs callbacks
  hwmon: (asb100) Various cleanups
  hwmon: VRM is not written to registers
  hwmon: (dme1737) fix Super-IO device ID override
  hwmon: (dme1737) fix divide-by-0
  hwmon: (abituguru3) Add AUX4 fan input for Abit IP35 Pro
  hwmon: Add support for Texas Instruments/Burr-Brown ADS7828
  hwmon: (adm9240) Add individual alarm files
  hwmon: (lm77) Add individual alarm files
  hwmon: Discard useless I2C driver IDs
  hwmon: (lm85) Make the pwmN_enable files writable
  hwmon: (lm85) Return standard values in pwmN_enable
  ...
This commit is contained in:
Linus Torvalds
2008-02-07 19:15:38 -08:00
60 changed files with 3682 additions and 1724 deletions
+36
View File
@@ -0,0 +1,36 @@
Kernel driver ads7828
=====================
Supported chips:
* Texas Instruments/Burr-Brown ADS7828
Prefix: 'ads7828'
Addresses scanned: I2C 0x48, 0x49, 0x4a, 0x4b
Datasheet: Publicly available at the Texas Instruments website :
http://focus.ti.com/lit/ds/symlink/ads7828.pdf
Authors:
Steve Hardy <steve@linuxrealtime.co.uk>
Module Parameters
-----------------
* se_input: bool (default Y)
Single ended operation - set to N for differential mode
* int_vref: bool (default Y)
Operate with the internal 2.5V reference - set to N for external reference
* vref_mv: int (default 2500)
If using an external reference, set this to the reference voltage in mV
Description
-----------
This driver implements support for the Texas Instruments ADS7828.
This device is a 12-bit 8-channel A-D converter.
It can operate in single ended mode (8 +ve inputs) or in differential mode,
where 4 differential pairs can be measured.
The chip also has the facility to use an external voltage reference. This
may be required if your hardware supplies the ADS7828 from a 5V supply, see
the datasheet for more details.
+1 -1
View File
@@ -30,7 +30,7 @@ Supported chips:
Datasheet: No longer be available
Authors:
Christophe Gauthron <chrisg@0-in.com>
Christophe Gauthron
Jean Delvare <khali@linux-fr.org>
+2 -2
View File
@@ -4,12 +4,12 @@ Kernel driver lm78
Supported chips:
* National Semiconductor LM78 / LM78-J
Prefix: 'lm78'
Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
Addresses scanned: I2C 0x28 - 0x2f, ISA 0x290 (8 I/O ports)
Datasheet: Publicly available at the National Semiconductor website
http://www.national.com/
* National Semiconductor LM79
Prefix: 'lm79'
Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
Addresses scanned: I2C 0x28 - 0x2f, ISA 0x290 (8 I/O ports)
Datasheet: Publicly available at the National Semiconductor website
http://www.national.com/
+8 -3
View File
@@ -4,8 +4,12 @@ Kernel driver lm87
Supported chips:
* National Semiconductor LM87
Prefix: 'lm87'
Addresses scanned: I2C 0x2c - 0x2f
Addresses scanned: I2C 0x2c - 0x2e
Datasheet: http://www.national.com/pf/LM/LM87.html
* Analog Devices ADM1024
Prefix: 'adm1024'
Addresses scanned: I2C 0x2c - 0x2e
Datasheet: http://www.analog.com/en/prod/0,2877,ADM1024,00.html
Authors:
Frodo Looijaard <frodol@dds.nl>,
@@ -19,11 +23,12 @@ Authors:
Description
-----------
This driver implements support for the National Semiconductor LM87.
This driver implements support for the National Semiconductor LM87
and the Analog Devices ADM1024.
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.
miscellaneous stuff. The ADM1024 is fully compatible.
Temperatures are measured in degrees Celsius. Each input has a high
and low alarm settings. A high limit produces an alarm when the value
+1 -1
View File
@@ -14,7 +14,7 @@ Lm-sensors
Core set of utilities that will allow you to obtain health information,
setup monitoring limits etc. You can get them on their homepage
http://www.lm-sensors.nu/ or as a package from your Linux distribution.
http://www.lm-sensors.org/ or as a package from your Linux distribution.
If from website:
Get lm-sensors from project web site. Please note, you need only userspace
+3 -2
View File
@@ -23,8 +23,9 @@ W83627DHG super I/O chips. We will refer to them collectively as Winbond chips.
The chips implement three temperature sensors, five fan rotation
speed sensors, ten analog voltage sensors (only nine for the 627DHG), one
VID (6 pins), alarms with beep warnings (control unimplemented), and
some automatic fan regulation strategies (plus manual fan control mode).
VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG), alarms with beep
warnings (control unimplemented), and some automatic fan regulation
strategies (plus manual fan control mode).
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
+1 -2
View File
@@ -73,5 +73,4 @@ doesn't help, you may just ignore the bogus VID reading with no harm done.
For further information on this driver see the w83781d driver documentation.
[1] http://www2.lm-sensors.nu/~lm78/cvs/browse.cgi/lm_sensors2/doc/vid
[1] http://www.lm-sensors.org/browser/lm-sensors/trunk/doc/vid
+8 -14
View File
@@ -4,20 +4,16 @@ Kernel driver w83781d
Supported chips:
* Winbond W83781D
Prefix: 'w83781d'
Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports)
Addresses scanned: I2C 0x28 - 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)
Addresses scanned: I2C 0x28 - 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 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
@@ -50,20 +46,18 @@ force_subclients=bus,caddr,saddr,saddr
Description
-----------
This driver implements support for the Winbond W83781D, W83782D, W83783S,
W83627HF chips, and the Asus AS99127F chips. We will refer to them
collectively as W8378* chips.
This driver implements support for the Winbond W83781D, W83782D, W83783S
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.
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
w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes
w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC)
w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes
w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no
@@ -143,9 +137,9 @@ Individual alarm and beep bits:
0x000400: in6
0x000800: fan3
0x001000: chassis
0x002000: temp3 (W83782D and W83627HF only)
0x010000: in7 (W83782D and W83627HF only)
0x020000: in8 (W83782D and W83627HF only)
0x002000: temp3 (W83782D only)
0x010000: in7 (W83782D only)
0x020000: in8 (W83782D 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
+54
View File
@@ -0,0 +1,54 @@
Kernel driver w83l786ng
=====================
Supported chips:
* Winbond W83L786NG/W83L786NR
Prefix: 'w83l786ng'
Addresses scanned: I2C 0x2e - 0x2f
Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L786NRNG09.pdf
Author: Kevin Lo <kevlo@kevlo.org>
Module Parameters
-----------------
* reset boolean
(default 0)
Use 'reset=1' to reset the chip (via index 0x40, bit 7). The default
behavior is no chip reset to preserve BIOS settings
Description
-----------
This driver implements support for Winbond W83L786NG/W83L786NR chips.
The driver implements two temperature sensors, two fan rotation speed
sensors, and three voltage sensors.
Temperatures are measured in degrees Celsius and measurement resolution is 1
degC for temp1 and temp2.
Fan rotation speeds are reported in RPM (rotations per minute). Fan readings
readings can be divided by a programmable divider (1, 2, 4, 8, 16, 32, 64
or 128 for fan 1/2) to give the readings more range or accuracy.
Voltage sensors (also known as IN sensors) report their values in millivolts.
An alarm is triggered if the voltage has crossed a programmable minimum
or maximum limit.
/sys files
----------
pwm[1-2] - this file stores PWM duty cycle or DC value (fan speed) in range:
0 (stop) to 255 (full)
pwm[1-2]_enable - this file controls mode of fan/temperature control:
* 0 Manual Mode
* 1 Thermal Cruise
* 2 Smart Fan II
* 4 FAN_SET
pwm[1-2]_mode - Select PWM of DC mode
* 0 DC
* 1 PWM
tolerance[1-2] - Value in degrees of Celsius (degC) for +- T
+1 -1
View File
@@ -95,4 +95,4 @@ of all affected systems, so the only safe solution was to prevent access to
the SMBus on all IBM systems (detected using DMI data.)
For additional information, read:
http://www2.lm-sensors.nu/~lm78/cvs/lm_sensors2/README.thinkpad
http://www.lm-sensors.org/browser/lm-sensors/trunk/README.thinkpad
+48 -14
View File
@@ -43,18 +43,12 @@ static char * __init dmi_string(const struct dmi_header *dm, u8 s)
* We have to be cautious here. We have seen BIOSes with DMI pointers
* pointing to completely the wrong place for example
*/
static int __init dmi_table(u32 base, int len, int num,
void (*decode)(const struct dmi_header *))
static void dmi_table(u8 *buf, int len, int num,
void (*decode)(const struct dmi_header *))
{
u8 *buf, *data;
u8 *data = buf;
int i = 0;
buf = dmi_ioremap(base, len);
if (buf == NULL)
return -1;
data = buf;
/*
* Stop when we see all the items the table claimed to have
* OR we run off the end of the table (also happens)
@@ -75,7 +69,23 @@ static int __init dmi_table(u32 base, int len, int num,
data += 2;
i++;
}
dmi_iounmap(buf, len);
}
static u32 dmi_base;
static u16 dmi_len;
static u16 dmi_num;
static int __init dmi_walk_early(void (*decode)(const struct dmi_header *))
{
u8 *buf;
buf = dmi_ioremap(dmi_base, dmi_len);
if (buf == NULL)
return -1;
dmi_table(buf, dmi_len, dmi_num, decode);
dmi_iounmap(buf, dmi_len);
return 0;
}
@@ -291,9 +301,9 @@ static int __init dmi_present(const char __iomem *p)
memcpy_fromio(buf, p, 15);
if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
u16 num = (buf[13] << 8) | buf[12];
u16 len = (buf[7] << 8) | buf[6];
u32 base = (buf[11] << 24) | (buf[10] << 16) |
dmi_num = (buf[13] << 8) | buf[12];
dmi_len = (buf[7] << 8) | buf[6];
dmi_base = (buf[11] << 24) | (buf[10] << 16) |
(buf[9] << 8) | buf[8];
/*
@@ -305,7 +315,7 @@ static int __init dmi_present(const char __iomem *p)
buf[14] >> 4, buf[14] & 0xF);
else
printk(KERN_INFO "DMI present.\n");
if (dmi_table(base,len, num, dmi_decode) == 0)
if (dmi_walk_early(dmi_decode) == 0)
return 0;
}
return 1;
@@ -489,3 +499,27 @@ int dmi_get_year(int field)
return year;
}
/**
* dmi_walk - Walk the DMI table and get called back for every record
* @decode: Callback function
*
* Returns -1 when the DMI table can't be reached, 0 on success.
*/
int dmi_walk(void (*decode)(const struct dmi_header *))
{
u8 *buf;
if (!dmi_available)
return -1;
buf = ioremap(dmi_base, dmi_len);
if (buf == NULL)
return -1;
dmi_table(buf, dmi_len, dmi_num, decode);
iounmap(buf);
return 0;
}
EXPORT_SYMBOL_GPL(dmi_walk);
+25 -5
View File
@@ -433,12 +433,12 @@ config SENSORS_LM85
will be called lm85.
config SENSORS_LM87
tristate "National Semiconductor LM87"
tristate "National Semiconductor LM87 and compatibles"
depends on I2C
select HWMON_VID
help
If you say yes here you get support for National Semiconductor LM87
sensor chips.
and Analog Devices ADM1024 sensor chips.
This driver can also be built as a module. If so, the module
will be called lm87.
@@ -588,6 +588,16 @@ config SENSORS_SMSC47B397
This driver can also be built as a module. If so, the module
will be called smsc47b397.
config SENSORS_ADS7828
tristate "Texas Instruments ADS7828"
depends on I2C
help
If you say yes here you get support for Texas Instruments ADS7828
12-bit 8-channel ADC device.
This driver can also be built as a module. If so, the module
will be called ads7828.
config SENSORS_THMC50
tristate "Texas Instruments THMC50 / Analog Devices ADM1022"
depends on I2C && EXPERIMENTAL
@@ -631,13 +641,13 @@ config SENSORS_VT8231
will be called vt8231.
config SENSORS_W83781D
tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F"
tristate "Winbond W83781D, W83782D, W83783S, Asus AS99127F"
depends on I2C
select HWMON_VID
help
If you say yes here you get support for the Winbond W8378x series
of sensor chips: the W83781D, W83782D, W83783S and W83627HF,
and the similar Asus AS99127F.
of sensor chips: the W83781D, W83782D and W83783S, and the similar
Asus AS99127F.
This driver can also be built as a module. If so, the module
will be called w83781d.
@@ -683,6 +693,16 @@ config SENSORS_W83L785TS
This driver can also be built as a module. If so, the module
will be called w83l785ts.
config SENSORS_W83L786NG
tristate "Winbond W83L786NG, W83L786NR"
depends on I2C && EXPERIMENTAL
help
If you say yes here you get support for the Winbond W83L786NG
and W83L786NR sensor chips.
This driver can also be built as a module. If so, the module
will be called w83l786ng.
config SENSORS_W83627HF
tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
select HWMON_VID
+2
View File
@@ -22,6 +22,7 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o
obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o
obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
obj-$(CONFIG_SENSORS_AMS) += ams/
@@ -68,6 +69,7 @@ obj-$(CONFIG_SENSORS_VT1211) += vt1211.o
obj-$(CONFIG_SENSORS_VT8231) += vt8231.o
obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o
obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG
+1
View File
@@ -528,6 +528,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
{ "AUX1 Fan", 33, 2, 60, 1, 0 },
{ "AUX2 Fan", 35, 2, 60, 1, 0 },
{ "AUX3 Fan", 36, 2, 60, 1, 0 },
{ "AUX4 Fan", 37, 2, 60, 1, 0 },
{ NULL, 0, 0, 0, 0, 0 } }
},
{ 0x001B, "unknown", {
-1
View File
@@ -115,7 +115,6 @@ static struct i2c_driver adm1021_driver = {
.driver = {
.name = "adm1021",
},
.id = I2C_DRIVERID_ADM1021,
.attach_adapter = adm1021_attach_adapter,
.detach_client = adm1021_detach_client,
};
+213 -178
View File
File diff suppressed because it is too large Load Diff
+360 -272
View File
File diff suppressed because it is too large Load Diff
+242 -259
View File
File diff suppressed because it is too large Load Diff
+26 -1
View File
@@ -141,7 +141,6 @@ static struct i2c_driver adm9240_driver = {
.driver = {
.name = "adm9240",
},
.id = I2C_DRIVERID_ADM9240,
.attach_adapter = adm9240_attach_adapter,
.detach_client = adm9240_detach_client,
};
@@ -415,6 +414,23 @@ static ssize_t show_alarms(struct device *dev,
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
static ssize_t show_alarm(struct device *dev,
struct device_attribute *attr, char *buf)
{
int bitnr = to_sensor_dev_attr(attr)->index;
struct adm9240_data *data = adm9240_update_device(dev);
return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
}
static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
/* vid */
static ssize_t show_vid(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -469,30 +485,39 @@ static struct attribute *adm9240_attributes[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in0_min.dev_attr.attr,
&sensor_dev_attr_in0_max.dev_attr.attr,
&sensor_dev_attr_in0_alarm.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in1_min.dev_attr.attr,
&sensor_dev_attr_in1_max.dev_attr.attr,
&sensor_dev_attr_in1_alarm.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_in2_min.dev_attr.attr,
&sensor_dev_attr_in2_max.dev_attr.attr,
&sensor_dev_attr_in2_alarm.dev_attr.attr,
&sensor_dev_attr_in3_input.dev_attr.attr,
&sensor_dev_attr_in3_min.dev_attr.attr,
&sensor_dev_attr_in3_max.dev_attr.attr,
&sensor_dev_attr_in3_alarm.dev_attr.attr,
&sensor_dev_attr_in4_input.dev_attr.attr,
&sensor_dev_attr_in4_min.dev_attr.attr,
&sensor_dev_attr_in4_max.dev_attr.attr,
&sensor_dev_attr_in4_alarm.dev_attr.attr,
&sensor_dev_attr_in5_input.dev_attr.attr,
&sensor_dev_attr_in5_min.dev_attr.attr,
&sensor_dev_attr_in5_max.dev_attr.attr,
&sensor_dev_attr_in5_alarm.dev_attr.attr,
&dev_attr_temp1_input.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_div.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan1_alarm.dev_attr.attr,
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr,
&sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan2_alarm.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_aout_output.attr,
&dev_attr_chassis_clear.attr,
+297
View File
@@ -0,0 +1,297 @@
/*
ads7828.c - lm_sensors driver for ads7828 12-bit 8-channel ADC
(C) 2007 EADS Astrium
This driver is based on the lm75 and other lm_sensors/hwmon drivers
Written by Steve Hardy <steve@linuxrealtime.co.uk>
Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads7828.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 <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
/* The ADS7828 registers */
#define ADS7828_NCH 8 /* 8 channels of 12-bit A-D supported */
#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */
#define ADS7828_CMD_SD_DIFF 0x00 /* Differential inputs */
#define ADS7828_CMD_PD0 0x0 /* Power Down between A-D conversions */
#define ADS7828_CMD_PD1 0x04 /* Internal ref OFF && A-D ON */
#define ADS7828_CMD_PD2 0x08 /* Internal ref ON && A-D OFF */
#define ADS7828_CMD_PD3 0x0C /* Internal ref ON && A-D ON */
#define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(ads7828);
/* Other module parameters */
static int se_input = 1; /* Default is SE, 0 == diff */
static int int_vref = 1; /* Default is internal ref ON */
static int vref_mv = ADS7828_INT_VREF_MV; /* set if vref != 2.5V */
module_param(se_input, bool, S_IRUGO);
module_param(int_vref, bool, S_IRUGO);
module_param(vref_mv, int, S_IRUGO);
/* Global Variables */
static u8 ads7828_cmd_byte; /* cmd byte without channel bits */
static unsigned int ads7828_lsb_resol; /* resolution of the ADC sample lsb */
/* Each client has this additional data */
struct ads7828_data {
struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock; /* mutex protect updates */
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH 12-bit samples */
};
/* Function declaration - necessary due to function dependencies */
static int ads7828_detect(struct i2c_adapter *adapter, int address, int kind);
/* The ADS7828 returns the 12-bit sample in two bytes,
these are read as a word then byte-swapped */
static u16 ads7828_read_value(struct i2c_client *client, u8 reg)
{
return swab16(i2c_smbus_read_word_data(client, reg));
}
static inline u8 channel_cmd_byte(int ch)
{
/* cmd byte C2,C1,C0 - see datasheet */
u8 cmd = (((ch>>1) | (ch&0x01)<<2)<<4);
cmd |= ads7828_cmd_byte;
return cmd;
}
/* Update data for the device (all 8 channels) */
static struct ads7828_data *ads7828_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ads7828_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
unsigned int ch;
dev_dbg(&client->dev, "Starting ads7828 update\n");
for (ch = 0; ch < ADS7828_NCH; ch++) {
u8 cmd = channel_cmd_byte(ch);
data->adc_input[ch] = ads7828_read_value(client, cmd);
}
data->last_updated = jiffies;
data->valid = 1;
}
mutex_unlock(&data->update_lock);
return data;
}
/* sysfs callback function */
static ssize_t show_in(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct ads7828_data *data = ads7828_update_device(dev);
/* Print value (in mV as specified in sysfs-interface documentation) */
return sprintf(buf, "%d\n", (data->adc_input[attr->index] *
ads7828_lsb_resol)/1000);
}
#define in_reg(offset)\
static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in,\
NULL, offset)
in_reg(0);
in_reg(1);
in_reg(2);
in_reg(3);
in_reg(4);
in_reg(5);
in_reg(6);
in_reg(7);
static struct attribute *ads7828_attributes[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_in3_input.dev_attr.attr,
&sensor_dev_attr_in4_input.dev_attr.attr,
&sensor_dev_attr_in5_input.dev_attr.attr,
&sensor_dev_attr_in6_input.dev_attr.attr,
&sensor_dev_attr_in7_input.dev_attr.attr,
NULL
};
static const struct attribute_group ads7828_group = {
.attrs = ads7828_attributes,
};
static int ads7828_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
return i2c_probe(adapter, &addr_data, ads7828_detect);
}
static int ads7828_detach_client(struct i2c_client *client)
{
struct ads7828_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &ads7828_group);
i2c_detach_client(client);
kfree(i2c_get_clientdata(client));
return 0;
}
/* This is the driver that will be inserted */
static struct i2c_driver ads7828_driver = {
.driver = {
.name = "ads7828",
},
.attach_adapter = ads7828_attach_adapter,
.detach_client = ads7828_detach_client,
};
/* This function is called by i2c_probe */
static int ads7828_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *client;
struct ads7828_data *data;
int err = 0;
const char *name = "";
/* Check we have a valid client */
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA))
goto 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 ads7828_read_value. */
data = kzalloc(sizeof(struct ads7828_data), GFP_KERNEL);
if (!data) {
err = -ENOMEM;
goto exit;
}
client = &data->client;
i2c_set_clientdata(client, data);
client->addr = address;
client->adapter = adapter;
client->driver = &ads7828_driver;
/* Now, we do the remaining detection. There is no identification
dedicated register so attempt to sanity check using knowledge of
the chip
- Read from the 8 channel addresses
- Check the top 4 bits of each result are not set (12 data bits)
*/
if (kind < 0) {
int ch;
for (ch = 0; ch < ADS7828_NCH; ch++) {
u16 in_data;
u8 cmd = channel_cmd_byte(ch);
in_data = ads7828_read_value(client, cmd);
if (in_data & 0xF000) {
printk(KERN_DEBUG
"%s : Doesn't look like an ads7828 device\n",
__FUNCTION__);
goto exit_free;
}
}
}
/* Determine the chip type - only one kind supported! */
if (kind <= 0)
kind = ads7828;
if (kind == ads7828)
name = "ads7828";
/* Fill in the remaining client fields, put it into the global list */
strlcpy(client->name, name, I2C_NAME_SIZE);
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
err = i2c_attach_client(client);
if (err)
goto exit_free;
/* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &ads7828_group);
if (err)
goto exit_detach;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
return 0;
exit_remove:
sysfs_remove_group(&client->dev.kobj, &ads7828_group);
exit_detach:
i2c_detach_client(client);
exit_free:
kfree(data);
exit:
return err;
}
static int __init sensors_ads7828_init(void)
{
/* Initialize the command byte according to module parameters */
ads7828_cmd_byte = se_input ?
ADS7828_CMD_SD_SE : ADS7828_CMD_SD_DIFF;
ads7828_cmd_byte |= int_vref ?
ADS7828_CMD_PD3 : ADS7828_CMD_PD1;
/* Calculate the LSB resolution */
ads7828_lsb_resol = (vref_mv*1000)/4096;
return i2c_add_driver(&ads7828_driver);
}
static void __exit sensors_ads7828_exit(void)
{
i2c_del_driver(&ads7828_driver);
}
MODULE_AUTHOR("Steve Hardy <steve@linuxrealtime.co.uk>");
MODULE_DESCRIPTION("ADS7828 driver");
MODULE_LICENSE("GPL");
module_init(sensors_ads7828_init);
module_exit(sensors_ads7828_exit);

Some files were not shown because too many files have changed in this diff Show More