Commit 2533fe7f authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge kroah.com:/home/greg/linux/BK/bleed-2.5

into kroah.com:/home/greg/linux/BK/i2c-new_drivers-2.6
parents 0e70f996 3c5e4412
Revision 3, 2003-10-04
Jean Delvare <khali@linux-fr.org>
Greg KH <greg@kroah.com>
This is a guide on how to convert I2C chip drivers from Linux 2.4 to
Linux 2.6. I have been using existing drivers (lm75, lm78) as examples.
Then I converted a driver myself (lm83) and updated this document.
There are two sets of points below. The first set concerns technical
changes. The second set concerns coding policy. Both are mandatory.
Although reading this guide will help you porting drivers, I suggest
you keep an eye on an already ported driver while porting your own
driver. This will help you a lot understanding what this guide
exactly means. Choose the chip driver that is the more similar to
yours for best results.
Technical changes:
* [Includes] Get rid of "version.h". Replace <linux/i2c-proc.h> with
<linux/i2c-sensor.h>. Includes typically look like that:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/i2c-sensor.h>
#include <linux/i2c-vid.h> /* if you need VRM support */
#include <asm/io.h> /* if you have I/O operations */
Some extra headers may be required for a given driver.
* [Addresses] SENSORS_I2C_END becomes I2C_CLIENT_END, SENSORS_ISA_END
becomes I2C_CLIENT_ISA_END.
* [Client data] Get rid of sysctl_id. Try using standard names for
register values (for example, temp_os becomes temp_max). You're
still relatively free here, but you *have* to follow the standard
names for sysfs files (see the Sysctl section below).
* [Function prototypes] The detect functions loses its flags
parameter. Sysctl (e.g. lm75_temp) and miscellaneous (e.g.
swap_bytes) functions are off the list of prototypes. This
usually leaves five prototypes:
static int lm75_attach_adapter(struct i2c_adapter *adapter);
static int lm75_detect(struct i2c_adapter *adapter, int address,
int kind);
static void lm75_init_client(struct i2c_client *client);
static int lm75_detach_client(struct i2c_client *client);
static void lm75_update_client(struct i2c_client *client);
* [Sysctl] All sysctl stuff is of course gone (defines, ctl_table
and functions). Instead, right after the static id definition
line, you have to define show and set functions for each sysfs
file. Only define set for writable values. Take a look at an
existing 2.6 driver for details (lm78 for example). Don't forget
to define the attributes for each file (this is that step that
links callback functions). Use the file names specified in
Documentation/i2c/sysfs-interface for the individual files. Also
convert the units these files read and write to the specified ones.
If you need to add a new type of file, please discuss it on the
sensors mailing list <sensors@stimpy.netroedge.com> by providing a
patch to the Documentation/i2c/sysfs-interface file.
* [Attach] For I2C drivers, the attach function should make sure
that the adapter's class has I2C_ADAP_CLASS_SMBUS, using the
following construct:
if (!(adapter->class & I2C_ADAP_CLASS_SMBUS))
return 0;
ISA-only drivers of course don't need this.
* [Detect] As mentioned earlier, the flags parameter is gone.
The type_name and client_name strings are replaced by a single
name string, which will be filled with a lowercase, short string
(typically the driver name, e.g. "lm75"). The errorN labels are
reduced to the number needed. If that number is 2 (i2c-only
drivers), it is advised that the labels are named exit and
exit_free. For i2c+isa drivers, labels should be named ERROR0,
ERROR1 and ERROR2. Don't forget to properly set err before
jumping to error labels. By the way, labels should be
left-aligned.
Use memset to fill the client and data area with 0x00.
Use i2c_set_clientdata to set the client data (as opposed to
a direct access to client->data).
Use strlcpy instead of strcpy to copy the client name.
Replace the sysctl directory registration by calls to
device_create_file. Move the driver initialization before any
sysfs file creation.
* [Detach] Get rid of data, remove the call to
i2c_deregister_entry.
* [Update] Don't access client->data directly, use
i2c_get_clientdata(client) instead.
* [Interface] Init function should not print anything. Make sure
there is a MODULE_LICENSE() line.
Coding policy:
* [Copyright] Use (C), not (c), for copyright.
* [Debug/log] Get rid of #ifdef DEBUG/#endif constructs whenever you
can. Calls to printk/pr_debug for debugging purposes are replaced
by calls to dev_dbg. Here is an example on how to call it (taken
from lm75_detect):
dev_dbg(&adapter->dev,
"lm75_detect called for an ISA bus adapter?!?\n");
Replace other printk calls with the dev_info, dev_err or dev_warn
function, as appropriate.
* [Constants] Constants defines (registers, conversions, initial
values) should be aligned. This greatly improves readability.
Same goes for variables declarations. Alignments are achieved by the
means of tabs, not spaces. Remember that tabs are set to 8 in the
Linux kernel code.
* [Structure definition] The name field should be standardized. All
lowercase and as simple as the driver name itself (e.g. "lm75").
* [Layout] Avoid extra empty lines between comments and what they
comment. Respect the coding style (see Documentation/CodingStyle),
in particular when it comes to placing curly braces.
......@@ -68,9 +68,7 @@ curr_max[1-n] Current max value
Fixed point XXXXX, divide by 1000 to get Amps.
Read/Write.
curr_min[1-n] Current min or hysteresis value.
Preferably a hysteresis value, reported as a absolute
current, NOT a delta from the max value.
curr_min[1-n] Current min value.
Fixed point XXXXX, divide by 1000 to get Amps.
Read/Write.
......@@ -144,25 +142,38 @@ sensor[1-3] Sensor type selection.
Integers 1,2,3, or thermistor Beta value (3435)
Read/Write.
temp_max[1-3] Temperature max value.
temp_max[1-4] Temperature max value.
Fixed point value in form XXXXX and should be divided by
1000 to get degrees Celsius.
Read/Write value.
temp_min[1-3] Temperature min or hysteresis value.
temp_min[1-3] Temperature min value.
Fixed point value in form XXXXX and should be divided by
1000 to get degrees Celsius. This is preferably a
hysteresis value, reported as a absolute temperature,
NOT a delta from the max value.
1000 to get degrees Celsius.
Read/Write value.
temp_input[1-3] Temperature input value.
temp_hyst[1-3] Temperature hysteresis value.
Fixed point value in form XXXXX and should be divided by
1000 to get degrees Celsius. Must be reported as an
absolute temperature, NOT a delta from the max value.
Read/Write value.
temp_input[1-4] Temperature input value.
Fixed point value in form XXXXX and should be divided by
1000 to get degrees Celsius.
Read only value.
temp_crit Temperature critical value, typically greater than all
temp_max values.
Fixed point value in form XXXXX and should be divided by
1000 to get degrees Celsius.
Common to all temperature channels.
Read/Write value.
If there are multiple temperature sensors, temp_*1 is
generally the sensor inside the chip itself, generally
reported as "motherboard temperature". temp_*2 and
temp_*3 are generally sensors external to the chip
reported as "motherboard temperature". temp_*2 to
temp_*4 are generally sensors external to the chip
itself, for example the thermal diode inside the CPU or
a thermistor nearby.
......
......@@ -24,16 +24,14 @@ all clients from it. Remember, a driver structure contains general access
routines, a client structure specific information like the actual I2C
address.
struct i2c_driver foo_driver
{
/* name */ "Foo version 2.3 and later driver",
/* id */ I2C_DRIVERID_FOO,
/* flags */ I2C_DF_NOTIFY,
/* attach_adapter */ &foo_attach_adapter,
/* detach_client */ &foo_detach_client,
/* command */ &foo_command, /* May be NULL */
/* inc_use */ &foo_inc_use, /* May be NULL */
/* dec_use */ &foo_dec_use /* May be NULL */
static struct i2c_driver foo_driver = {
.owner = THIS_MODULE,
.name = "Foo version 2.3 driver",
.id = I2C_DRIVERID_FOO, /* usually from i2c-id.h */
.flags = I2C_DF_NOTIFY,
.attach_adapter = &foo_attach_adapter,
.detach_client = &foo_detach_client,
.command = &foo_command /* may be NULL */
}
The name can be chosen freely, and may be upto 40 characters long. Please
......@@ -50,43 +48,8 @@ This is almost always what you want.
All other fields are for call-back functions which will be explained
below.
Module usage count
==================
If your driver can also be compiled as a module, there are moments at
which the module can not be removed from memory. For example, when you
are doing a lengthy transaction, or when you create a /proc directory,
and some process has entered that directory (this last case is the
main reason why these call-backs were introduced).
To increase or decrease the module usage count, you can use the
MOD_{INC,DEC}_USE_COUNT macros. They must be called from the module
which needs to get its usage count changed; that is why each driver
module has to implement its own callback.
void foo_inc_use (struct i2c_client *client)
{
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
}
void foo_dec_use (struct i2c_client *client)
{
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
}
Do not call these call-back functions directly; instead, use one of the
following functions defined in i2c.h:
void i2c_inc_use_client(struct i2c_client *);
void i2c_dec_use_client(struct i2c_client *);
You should *not* increase the module count just because a device is
detected and a client created. This would make it impossible to remove
an adapter driver!
There use to be two additional fields in this structure, inc_use et dec_use,
for module usage count, but these fields were obsoleted and removed.
Extra client data
......
......@@ -18,10 +18,8 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ------------------------------------------------------------------------- */
/* With some changes from Kysti Mlkki <kmalkki@cc.hut.fi> and even
Frodo Looijaard <frodol@dds.nl> */
/* $Id: i2c-algo-bit.c,v 1.44 2003/01/21 08:08:16 kmalkki Exp $ */
/* With some changes from Frodo Looijaard <frodol@dds.nl>, Kysti Mlkki
<kmalkki@cc.hut.fi> and Jean Delvare <khali@linux-fr.org> */
/* #define DEBUG 1 */
......@@ -87,8 +85,10 @@ static inline int sclhi(struct i2c_algo_bit_data *adap)
setscl(adap,1);
/* Not all adapters have scl sense line... */
if (adap->getscl == NULL )
if (adap->getscl == NULL ) {
udelay(adap->udelay);
return 0;
}
start=jiffies;
while (! getscl(adap) ) {
......@@ -222,68 +222,72 @@ static int i2c_inb(struct i2c_adapter *i2c_adap)
*/
static int test_bus(struct i2c_algo_bit_data *adap, char* name) {
int scl,sda;
if (adap->getscl==NULL)
printk(KERN_INFO "i2c-algo-bit.o: Testing SDA only, "
"SCL is not readable.\n");
sda=getsda(adap);
if (adap->getscl==NULL) {
printk(KERN_WARNING "i2c-algo-bit.o: Warning: Adapter can't read from clock line - skipping test.\n");
return 0;
}
scl=getscl(adap);
printk(KERN_INFO "i2c-algo-bit.o: Adapter: %s scl: %d sda: %d -- testing...\n",
name,getscl(adap),getsda(adap));
scl=(adap->getscl==NULL?1:getscl(adap));
printk(KERN_DEBUG "i2c-algo-bit.o: (0) scl=%d, sda=%d\n",scl,sda);
if (!scl || !sda ) {
printk(KERN_INFO " i2c-algo-bit.o: %s seems to be busy.\n",name);
printk(KERN_WARNING "i2c-algo-bit.o: %s seems to be busy.\n", name);
goto bailout;
}
sdalo(adap);
printk(KERN_DEBUG "i2c-algo-bit.o:1 scl: %d sda: %d \n",getscl(adap),
getsda(adap));
if ( 0 != getsda(adap) ) {
printk(KERN_WARNING "i2c-algo-bit.o: %s SDA stuck high!\n",name);
sdahi(adap);
sda=getsda(adap);
scl=(adap->getscl==NULL?1:getscl(adap));
printk(KERN_DEBUG "i2c-algo-bit.o: (1) scl=%d, sda=%d\n",scl,sda);
if ( 0 != sda ) {
printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck high!\n");
goto bailout;
}
if ( 0 == getscl(adap) ) {
printk(KERN_WARNING "i2c-algo-bit.o: %s SCL unexpected low while pulling SDA low!\n",
name);
if ( 0 == scl ) {
printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low "
"while pulling SDA low!\n");
goto bailout;
}
sdahi(adap);
printk(KERN_DEBUG "i2c-algo-bit.o:2 scl: %d sda: %d \n",getscl(adap),
getsda(adap));
if ( 0 == getsda(adap) ) {
printk(KERN_WARNING "i2c-algo-bit.o: %s SDA stuck low!\n",name);
sdahi(adap);
sda=getsda(adap);
scl=(adap->getscl==NULL?1:getscl(adap));
printk(KERN_DEBUG "i2c-algo-bit.o: (2) scl=%d, sda=%d\n",scl,sda);
if ( 0 == sda ) {
printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck low!\n");
goto bailout;
}
if ( 0 == getscl(adap) ) {
printk(KERN_WARNING "i2c-algo-bit.o: %s SCL unexpected low while SDA high!\n",
name);
goto bailout;
if ( 0 == scl ) {
printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low "
"while pulling SDA high!\n");
goto bailout;
}
scllo(adap);
printk(KERN_DEBUG "i2c-algo-bit.o:3 scl: %d sda: %d \n",getscl(adap),
getsda(adap));
if ( 0 != getscl(adap) ) {
printk(KERN_WARNING "i2c-algo-bit.o: %s SCL stuck high!\n",name);
sclhi(adap);
sda=getsda(adap);
scl=(adap->getscl==NULL?0:getscl(adap));
printk(KERN_DEBUG "i2c-algo-bit.o: (3) scl=%d, sda=%d\n",scl,sda);
if ( 0 != scl ) {
printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck high!\n");
goto bailout;
}
if ( 0 == getsda(adap) ) {
printk(KERN_WARNING "i2c-algo-bit.o: %s SDA unexpected low while pulling SCL low!\n",
name);
if ( 0 == sda ) {
printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low "
"while pulling SCL low!\n");
goto bailout;
}
sclhi(adap);
printk(KERN_DEBUG "i2c-algo-bit.o:4 scl: %d sda: %d \n",getscl(adap),
getsda(adap));
if ( 0 == getscl(adap) ) {
printk(KERN_WARNING "i2c-algo-bit.o: %s SCL stuck low!\n",name);
sclhi(adap);
sda=getsda(adap);
scl=(adap->getscl==NULL?1:getscl(adap));
printk(KERN_DEBUG "i2c-algo-bit.o: (4) scl=%d, sda=%d\n",scl,sda);
if ( 0 == scl ) {
printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck low!\n");
goto bailout;
}
if ( 0 == getsda(adap) ) {
printk(KERN_WARNING "i2c-algo-bit.o: %s SDA unexpected low while SCL high!\n",
name);
if ( 0 == sda ) {
printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low "
"while pulling SCL high!\n");
goto bailout;
}
printk(KERN_INFO "i2c-algo-bit.o: %s passed test.\n",name);
......
......@@ -161,11 +161,12 @@ config I2C_PIIX4
help
If you say yes to this option, support will be included for the Intel
PIIX4 family of mainboard I2C interfaces. Specifically, the following
versions of the chipset is supported:
versions of the chipset are supported:
Intel PIIX4
Intel 440MX
Serverworks OSB4
Serverworks CSB5
Serverworks CSB6
SMSC Victory66
This driver can also be built as a module. If so, the module
......@@ -309,6 +310,7 @@ config I2C_VIAPRO
8233
8233A
8235
8237
This driver can also be built as a module. If so, the module
will be called i2c-viapro.
......
......@@ -22,7 +22,7 @@
/*
Supports:
Intel PIIX4, 440MX
Serverworks OSB4, CSB5
Serverworks OSB4, CSB5, CSB6
SMSC Victory66
Note: we assume there can only be one device, with one SMBus interface.
......@@ -422,6 +422,13 @@ static struct pci_device_id piix4_ids[] = {
.subdevice = PCI_ANY_ID,
.driver_data = 0,
},
{
.vendor = PCI_VENDOR_ID_SERVERWORKS,
.device = PCI_DEVICE_ID_SERVERWORKS_CSB6,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = 0,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_82443MX_3,
......
/*
i2c-savage4.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>,
Philip Edelbrock <phil@netroedge.com>,
Ralph Metzler <rjkm@thp.uni-koeln.de>, and
Copyright (C) 1998-2003 The LM Sensors Team
Alexander Wold <awold@bigfoot.com>
Mark D. Studebaker <mdsxyz123@yahoo.com>
Based on code written by Ralph Metzler <rjkm@thp.uni-koeln.de> and
Simon Vogl
Based on i2c-voodoo3.c.
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
......@@ -195,9 +193,7 @@ static void __exit i2c_savage4_exit(void)
pci_unregister_driver(&savage4_driver);
}
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
"Philip Edelbrock <phil@netroedge.com>, "
"Ralph Metzler <rjkm@thp.uni-koeln.de>, "
MODULE_AUTHOR("Alexander Wold <awold@bigfoot.com> "
"and Mark D. Studebaker <mdsxyz123@yahoo.com>");
MODULE_DESCRIPTION("Savage4 I2C/SMBus driver");
MODULE_LICENSE("GPL");
......
......@@ -29,6 +29,7 @@
8233
8233A (0x3147 and 0x3177)
8235
8237
Note: we assume there can only be one device, with one SMBus interface.
*/
......@@ -434,6 +435,13 @@ static struct pci_device_id vt596_ids[] = {
.subdevice = PCI_ANY_ID,
.driver_data = SMBBA3
},
{
.vendor = PCI_VENDOR_ID_VIA,
.device = PCI_DEVICE_ID_VIA_8237,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = SMBBA3
},
{
.vendor = PCI_VENDOR_ID_VIA,
.device = PCI_DEVICE_ID_VIA_8231_4,
......
......@@ -68,6 +68,17 @@ config SENSORS_LM78
This driver can also be built as a module. If so, the module
will be called lm78.
config SENSORS_LM83
tristate "National Semiconductor LM83"
depends on I2C && EXPERIMENTAL
select I2C_SENSOR
help
If you say yes here you get support for National Semiconductor
LM83 sensor chips.
This driver can also be built as a module. If so, the module
will be called lm83.
config SENSORS_LM85
tristate "National Semiconductor LM85 and compatibles"
depends on I2C && EXPERIMENTAL
......
......@@ -10,5 +10,6 @@ obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o
obj-$(CONFIG_SENSORS_IT87) += it87.o
obj-$(CONFIG_SENSORS_LM75) += lm75.o
obj-$(CONFIG_SENSORS_LM78) += lm78.o
obj-$(CONFIG_SENSORS_LM83) += lm83.o
obj-$(CONFIG_SENSORS_LM85) += lm85.o
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
......@@ -343,7 +343,6 @@ static ssize_t show_temp(struct device *dev, char *buf, int nr)
it87_update_client(client);
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])*100 );
}
/* more like overshoot temperature */
static ssize_t show_temp_max(struct device *dev, char *buf, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
......@@ -351,7 +350,6 @@ static ssize_t show_temp_max(struct device *dev, char *buf, int nr)
it87_update_client(client);
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])*100);
}
/* more like hysteresis temperature */
static ssize_t show_temp_min(struct device *dev, char *buf, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
......@@ -414,7 +412,6 @@ show_temp_offset(1);
show_temp_offset(2);
show_temp_offset(3);
/* more like overshoot temperature */
static ssize_t show_sensor(struct device *dev, char *buf, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
......@@ -563,15 +560,15 @@ show_fan_offset(1);
show_fan_offset(2);
show_fan_offset(3);
/* Alarm */
static ssize_t show_alarm(struct device *dev, char *buf)
/* Alarms */
static ssize_t show_alarms(struct device *dev, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct it87_data *data = i2c_get_clientdata(client);
it87_update_client(client);
return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms));
}
static DEVICE_ATTR(alarm, S_IRUGO | S_IWUSR, show_alarm, NULL);
static DEVICE_ATTR(alarms, S_IRUGO | S_IWUSR, show_alarms, NULL);
/* This function is called when:
* it87_driver is inserted (when this module is loaded), for each
......@@ -751,7 +748,7 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind)
device_create_file(&new_client->dev, &dev_attr_fan_div1);
device_create_file(&new_client->dev, &dev_attr_fan_div2);
device_create_file(&new_client->dev, &dev_attr_fan_div3);
device_create_file(&new_client->dev, &dev_attr_alarm);
device_create_file(&new_client->dev, &dev_attr_alarms);
return 0;
......
......@@ -116,7 +116,7 @@ set(temp_max, LM75_REG_TEMP_OS);
set(temp_hyst, LM75_REG_TEMP_HYST);
static DEVICE_ATTR(temp_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
static DEVICE_ATTR(temp_min, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst);
static DEVICE_ATTR(temp_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst);
static DEVICE_ATTR(temp_input, S_IRUGO, show_temp_input, NULL);
static int lm75_attach_adapter(struct i2c_adapter *adapter)
......@@ -209,7 +209,7 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
/* Register sysfs hooks */
device_create_file(&new_client->dev, &dev_attr_temp_max);
device_create_file(&new_client->dev, &dev_attr_temp_min);
device_create_file(&new_client->dev, &dev_attr_temp_hyst);
device_create_file(&new_client->dev, &dev_attr_temp_input);
return 0;
......
......@@ -367,7 +367,7 @@ static ssize_t set_temp_hyst(struct device *dev, const char *buf, size_t count)
static DEVICE_ATTR(temp_input, S_IRUGO, show_temp, NULL)
static DEVICE_ATTR(temp_max, S_IRUGO | S_IWUSR,
show_temp_over, set_temp_over)
static DEVICE_ATTR(temp_min, S_IRUGO | S_IWUSR,
static DEVICE_ATTR(temp_hyst, S_IRUGO | S_IWUSR,
show_temp_hyst, set_temp_hyst)
/* 3 Fans */
......@@ -674,8 +674,8 @@ int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
device_create_file(&new_client->dev, &dev_attr_in_min6);
device_create_file(&new_client->dev, &dev_attr_in_max6);
device_create_file(&new_client->dev, &dev_attr_temp_input);
device_create_file(&new_client->dev, &dev_attr_temp_min);
device_create_file(&new_client->dev, &dev_attr_temp_max);
device_create_file(&new_client->dev, &dev_attr_temp_hyst);
device_create_file(&new_client->dev, &dev_attr_fan_input1);
device_create_file(&new_client->dev, &dev_attr_fan_min1);
device_create_file(&new_client->dev, &dev_attr_fan_div1);
......
/*
* lm83.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring
* Copyright (C) 2003 Jean Delvare <khali@linux-fr.org>
*
* 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).
*
* 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/i2c.h>
#include <linux/i2c-sensor.h>
/*
* Addresses to scan
* Address is selected using 2 three-level pins, resulting in 9 possible
* addresses.
*/
static unsigned short normal_i2c[] = { I2C_CLIENT_END };
static unsigned short normal_i2c_range[] = { 0x18, 0x1a, 0x29, 0x2b,
0x4c, 0x4e, I2C_CLIENT_END };
static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };
/*
* Insmod parameters
*/
SENSORS_INSMOD_1(lm83);
/*
* 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, initial values and various macros
* The LM83 uses signed 8-bit values.
*/
#define TEMP_FROM_REG(val) ((val > 127 ? val-256 : val) * 1000)
#define TEMP_TO_REG(val) ((val < 0 ? val+256 : val) / 1000)
#define LM83_INIT_HIGH 100
#define LM83_INIT_CRIT 120
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,
int kind);
static void lm83_init_client(struct i2c_client *client);
static int lm83_detach_client(struct i2c_client *client);
static void lm83_update_client(struct i2c_client *client);
/*
* Driver data (common to all clients)
*/
static struct i2c_driver lm83_driver = {
.owner = THIS_MODULE,
.name = "lm83",
.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 semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
/* registers values */
u8 temp_input[4];
u8 temp_high[4];
u8 temp_crit;
u16 alarms; /* bitvector, combined */
};
/*
* Internal variables
*/
static int lm83_id = 0;
/*
* Sysfs stuff
*/
#define show_temp(suffix, value) \
static ssize_t show_temp_##suffix(struct device *dev, char *buf) \
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct lm83_data *data = i2c_get_clientdata(client); \
lm83_update_client(client); \
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \
}
show_temp(input1, temp_input[0]);
show_temp(input2, temp_input[1]);
show_temp(input3, temp_input[2]);
show_temp(input4, temp_input[3]);
show_temp(high1, temp_high[0]);
show_temp(high2, temp_high[1]);
show_temp(high3, temp_high[2]);
show_temp(high4, temp_high[3]);
show_temp(crit, temp_crit);
#define set_temp(suffix, value, reg) \
static ssize_t set_temp_##suffix(struct device *dev, const char *buf, \
size_t count) \
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct lm83_data *data = i2c_get_clientdata(client); \
data->value = TEMP_TO_REG(simple_strtoul(buf, NULL, 10)); \
i2c_smbus_write_byte_data(client, reg, data->value); \
return count; \
}
set_temp(high1, temp_high[0], LM83_REG_W_LOCAL_HIGH);
set_temp(high2, temp_high[1], LM83_REG_W_REMOTE1_HIGH);
set_temp(high3, temp_high[2], LM83_REG_W_REMOTE2_HIGH);
set_temp(high4, temp_high[3], LM83_REG_W_REMOTE3_HIGH);
set_temp(crit, temp_crit, LM83_REG_W_TCRIT);
static ssize_t show_alarms(struct device *dev, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm83_data *data = i2c_get_clientdata(client);
lm83_update_client(client);
return sprintf(buf, "%d\n", data->alarms);
}
static DEVICE_ATTR(temp_input1, S_IRUGO, show_temp_input1, NULL);
static DEVICE_ATTR(temp_input2, S_IRUGO, show_temp_input2, NULL);
static DEVICE_ATTR(temp_input3, S_IRUGO, show_temp_input3, NULL);
static DEVICE_ATTR(temp_input4, S_IRUGO, show_temp_input4, NULL);
static DEVICE_ATTR(temp_max1, S_IWUSR | S_IRUGO, show_temp_high1,
set_temp_high1);
static DEVICE_ATTR(temp_max2, S_IWUSR | S_IRUGO, show_temp_high2,
set_temp_high2);
static DEVICE_ATTR(temp_max3, S_IWUSR | S_IRUGO, show_temp_high3,
set_temp_high3);
static DEVICE_ATTR(temp_max4, S_IWUSR | S_IRUGO, show_temp_high4,
set_temp_high4);
static DEVICE_ATTR(temp_crit, S_IWUSR | S_IRUGO, show_temp_crit,
set_temp_crit);
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
/*
* Real code
*/
static int lm83_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_ADAP_CLASS_SMBUS))
return 0;
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,
int kind)
{
struct i2c_client *new_client;
struct lm83_data *data;
int err = 0;
const char *name = "";
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
goto exit;
if (!(new_client = kmalloc(sizeof(struct i2c_client) +
sizeof(struct lm83_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
memset(new_client, 0x00, sizeof(struct i2c_client) +
sizeof(struct lm83_data));
/* The LM83-specific data is placed right after the common I2C
* client data. */
data = (struct lm83_data *) (new_client + 1);
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
new_client->driver = &lm83_driver;
new_client->flags = 0;
/* Now we do the detection and identification. 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. */
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)) {
dev_dbg(&client->dev,
"LM83 detection failed at 0x%02x.\n", address);
goto exit_free;
}
}
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;
name = "lm83";
}
}
if (kind <= 0) { /* identification failed */
dev_info(&adapter->dev,
"Unsupported chip (man_id=0x%02X, "
"chip_id=0x%02X).\n", man_id, chip_id);
goto exit_free;
}
}
/* We can fill in the remaining client fields */
strlcpy(new_client->name, name, I2C_NAME_SIZE);
new_client->id = lm83_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 exit_free;
/* Initialize the LM83 chip */
lm83_init_client(new_client);
/* Register sysfs hooks */
device_create_file(&new_client->dev, &dev_attr_temp_input1);
device_create_file(&new_client->dev, &dev_attr_temp_input2);
device_create_file(&new_client->dev, &dev_attr_temp_input3);
device_create_file(&new_client->dev, &dev_attr_temp_input4);
device_create_file(&new_client->dev, &dev_attr_temp_max1);
device_create_file(&new_client->dev, &dev_attr_temp_max2);
device_create_file(&new_client->dev, &dev_attr_temp_max3);
device_create_file(&new_client->dev, &dev_attr_temp_max4);
device_create_file(&new_client->dev, &dev_attr_temp_crit);
device_create_file(&new_client->dev, &dev_attr_alarms);
return 0;
exit_free:
kfree(new_client);
exit:
return err;
}
static void lm83_init_client(struct i2c_client *client)
{
int nr;
for (nr = 0; nr < 4; nr++)
i2c_smbus_write_byte_data(client, LM83_REG_W_HIGH[nr],
TEMP_TO_REG(LM83_INIT_HIGH));
i2c_smbus_write_byte_data(client, LM83_REG_W_TCRIT,
TEMP_TO_REG(LM83_INIT_CRIT));
}
static int lm83_detach_client(struct i2c_client *client)
{
int err;
if ((err = i2c_detach_client(client))) {
dev_err(&client->dev,
"Client deregistration failed, client not detached.\n");
return err;
}
kfree(client);
return 0;
}
static void lm83_update_client(struct i2c_client *client)
{
struct lm83_data *data = i2c_get_clientdata(client);
down(&data->update_lock);
if ((jiffies - data->last_updated > HZ * 2) ||
(jiffies < data->last_updated) ||
!data->valid) {
int nr;
dev_dbg(&client->dev, "Updating lm83 data.\n");
for (nr = 0; nr < 4 ; nr++) {
data->temp_input[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->temp_crit =
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 int __init sensors_lm83_init(void)
{
return i2c_add_driver(&lm83_driver);
}
static void __exit sensors_lm83_exit(void)
{
i2c_del_driver(&lm83_driver);
}
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
MODULE_DESCRIPTION("LM83 driver");
MODULE_LICENSE("GPL");
module_init(sensors_lm83_init);
module_exit(sensors_lm83_exit);
......@@ -496,21 +496,19 @@ static ssize_t show_temp(struct device *dev, char *buf, int nr) {
via686a_update_client(client);
return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr])*100 );
}
/* more like overshoot temperature */
static ssize_t show_temp_max(struct device *dev, char *buf, int nr) {
static ssize_t show_temp_over(struct device *dev, char *buf, int nr) {
struct i2c_client *client = to_i2c_client(dev);
struct via686a_data *data = i2c_get_clientdata(client);
via686a_update_client(client);
return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr])*100);
}
/* more like hysteresis temperature */
static ssize_t show_temp_min(struct device *dev, char *buf, int nr) {
static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) {
struct i2c_client *client = to_i2c_client(dev);
struct via686a_data *data = i2c_get_clientdata(client);
via686a_update_client(client);
return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr])*100);
}
static ssize_t set_temp_max(struct device *dev, const char *buf,
static ssize_t set_temp_over(struct device *dev, const char *buf,
size_t count, int nr) {
struct i2c_client *client = to_i2c_client(dev);
struct via686a_data *data = i2c_get_clientdata(client);
......@@ -519,7 +517,7 @@ static ssize_t set_temp_max(struct device *dev, const char *buf,
via686a_write_value(client, VIA686A_REG_TEMP_OVER(nr), data->temp_over[nr]);
return count;
}
static ssize_t set_temp_min(struct device *dev, const char *buf,
static ssize_t set_temp_hyst(struct device *dev, const char *buf,
size_t count, int nr) {
struct i2c_client *client = to_i2c_client(dev);
struct via686a_data *data = i2c_get_clientdata(client);
......@@ -534,30 +532,30 @@ static ssize_t show_temp_##offset (struct device *dev, char *buf) \
return show_temp(dev, buf, 0x##offset - 1); \
} \
static ssize_t \
show_temp_##offset##_max (struct device *dev, char *buf) \
show_temp_##offset##_over (struct device *dev, char *buf) \
{ \
return show_temp_max(dev, buf, 0x##offset - 1); \
return show_temp_over(dev, buf, 0x##offset - 1); \
} \
static ssize_t \
show_temp_##offset##_min (struct device *dev, char *buf) \
show_temp_##offset##_hyst (struct device *dev, char *buf) \
{ \
return show_temp_min(dev, buf, 0x##offset - 1); \
return show_temp_hyst(dev, buf, 0x##offset - 1); \
} \
static ssize_t set_temp_##offset##_max (struct device *dev, \
static ssize_t set_temp_##offset##_over (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_temp_max(dev, buf, count, 0x##offset - 1); \
return set_temp_over(dev, buf, count, 0x##offset - 1); \
} \
static ssize_t set_temp_##offset##_min (struct device *dev, \
static ssize_t set_temp_##offset##_hyst (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_temp_min(dev, buf, count, 0x##offset - 1); \
return set_temp_hyst(dev, buf, count, 0x##offset - 1); \
} \
static DEVICE_ATTR(temp_input##offset, S_IRUGO, show_temp_##offset, NULL) \
static DEVICE_ATTR(temp_max##offset, S_IRUGO | S_IWUSR, \
show_temp_##offset##_max, set_temp_##offset##_max) \
static DEVICE_ATTR(temp_min##offset, S_IRUGO | S_IWUSR, \
show_temp_##offset##_min, set_temp_##offset##_min)
show_temp_##offset##_over, set_temp_##offset##_over) \
static DEVICE_ATTR(temp_hyst##offset, S_IRUGO | S_IWUSR, \
show_temp_##offset##_hyst, set_temp_##offset##_hyst)
show_temp_offset(1);
show_temp_offset(2);
......@@ -637,14 +635,14 @@ static DEVICE_ATTR(fan_div##offset, S_IRUGO | S_IWUSR, \
show_fan_offset(1);
show_fan_offset(2);
/* Alarm */
static ssize_t show_alarm(struct device *dev, char *buf) {
/* Alarms */
static ssize_t show_alarms(struct device *dev, char *buf) {
struct i2c_client *client = to_i2c_client(dev);
struct via686a_data *data = i2c_get_clientdata(client);
via686a_update_client(client);
return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms));
}
static DEVICE_ATTR(alarm, S_IRUGO | S_IWUSR, show_alarm, NULL);
static DEVICE_ATTR(alarms, S_IRUGO | S_IWUSR, show_alarms, NULL);
/* 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 */
......@@ -760,16 +758,16 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind)
device_create_file(&new_client->dev, &dev_attr_temp_max1);
device_create_file(&new_client->dev, &dev_attr_temp_max2);
device_create_file(&new_client->dev, &dev_attr_temp_max3);
device_create_file(&new_client->dev, &dev_attr_temp_min1);
device_create_file(&new_client->dev, &dev_attr_temp_min2);
device_create_file(&new_client->dev, &dev_attr_temp_min3);
device_create_file(&new_client->dev, &dev_attr_temp_hyst1);
device_create_file(&new_client->dev, &dev_attr_temp_hyst2);
device_create_file(&new_client->dev, &dev_attr_temp_hyst3);
device_create_file(&new_client->dev, &dev_attr_fan_input1);
device_create_file(&new_client->dev, &dev_attr_fan_input2);
device_create_file(&new_client->dev, &dev_attr_fan_min1);
device_create_file(&new_client->dev, &dev_attr_fan_min2);
device_create_file(&new_client->dev, &dev_attr_fan_div1);
device_create_file(&new_client->dev, &dev_attr_fan_div2);
device_create_file(&new_client->dev, &dev_attr_alarm);
device_create_file(&new_client->dev, &dev_attr_alarms);
return 0;
......
......@@ -309,11 +309,11 @@ struct w83781d_data {
u8 fan[3]; /* Register value */
u8 fan_min[3]; /* Register value */
u8 temp;
u8 temp_min; /* Register value */
u8 temp_max; /* Register value */
u8 temp_hyst; /* Register value */
u16 temp_add[2]; /* Register value */
u16 temp_max_add[2]; /* Register value */
u16 temp_min_add[2]; /* Register value */
u16 temp_hyst_add[2]; /* Register value */
u8 fan_div[3]; /* Register encoding, shifted right */
u8 vid; /* Register encoding, combined */
u32 alarms; /* Register encoding, combined */
......@@ -510,8 +510,8 @@ static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
} \
}
show_temp_reg(temp);
show_temp_reg(temp_min);
show_temp_reg(temp_max);
show_temp_reg(temp_hyst);
#define store_temp_reg(REG, reg) \
static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \
......@@ -538,8 +538,8 @@ static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t cou
\
return count; \
}
store_temp_reg(OVER, min);
store_temp_reg(HYST, max);
store_temp_reg(OVER, max);
store_temp_reg(HYST, hyst);
#define sysfs_temp_offset(offset) \
static ssize_t \
......@@ -562,8 +562,8 @@ static DEVICE_ATTR(temp_##reg##offset, S_IRUGO| S_IWUSR, show_regs_temp_##reg##o
#define sysfs_temp_offsets(offset) \
sysfs_temp_offset(offset); \
sysfs_temp_reg_offset(min, offset); \
sysfs_temp_reg_offset(max, offset);
sysfs_temp_reg_offset(max, offset); \
sysfs_temp_reg_offset(hyst, offset);
sysfs_temp_offsets(1);
sysfs_temp_offsets(2);
......@@ -573,7 +573,7 @@ sysfs_temp_offsets(3);
do { \
device_create_file(&client->dev, &dev_attr_temp_input##offset); \
device_create_file(&client->dev, &dev_attr_temp_max##offset); \
device_create_file(&client->dev, &dev_attr_temp_min##offset); \
device_create_file(&client->dev, &dev_attr_temp_hyst##offset); \
} while (0)
static ssize_t
......@@ -1865,15 +1865,15 @@ w83781d_update_client(struct i2c_client *client)
}
data->temp = w83781d_read_value(client, W83781D_REG_TEMP(1));
data->temp_min =
w83781d_read_value(client, W83781D_REG_TEMP_OVER(1));
data->temp_max =
w83781d_read_value(client, W83781D_REG_TEMP_OVER(1));
data->temp_hyst =
w83781d_read_value(client, W83781D_REG_TEMP_HYST(1));
data->temp_add[0] =
w83781d_read_value(client, W83781D_REG_TEMP(2));
data->temp_max_add[0] =
w83781d_read_value(client, W83781D_REG_TEMP_OVER(2));
data->temp_min_add[0] =
data->temp_hyst_add[0] =
w83781d_read_value(client, W83781D_REG_TEMP_HYST(2));
if (data->type != w83783s && data->type != w83697hf) {
data->temp_add[1] =
......@@ -1881,7 +1881,7 @@ w83781d_update_client(struct i2c_client *client)
data->temp_max_add[1] =
w83781d_read_value(client,
W83781D_REG_TEMP_OVER(3));
data->temp_min_add[1] =
data->temp_hyst_add[1] =
w83781d_read_value(client,
W83781D_REG_TEMP_HYST(3));
}
......
......@@ -153,6 +153,7 @@
#define I2C_DRIVERID_FS451 1037
#define I2C_DRIVERID_W83627HF 1038
#define I2C_DRIVERID_LM85 1039
#define I2C_DRIVERID_LM83 1040
/*
* ---- Adapter types ----------------------------------------------------
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment