Commit a343ff96 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/gregkh/linux/i2c-2.6

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 688fd9b6 68fb0f04
MODULE: i2c-stub
DESCRIPTION:
This module is a very simple fake I2C/SMBus driver. It implements three
types of SMBus commands: write quick, (r/w) byte data, and (r/w) word data.
No hardware is needed nor associated with this module. It will accept write
quick commands to all addresses; it will respond to the other commands (also
to all addresses) by reading from or writing to an array in memory. It will
also spam the kernel logs for every command it handles.
The typical use-case is like this:
1. load this module
2. use i2cset (from lm_sensors project) to pre-load some data
3. load the target sensors chip driver module
4. observe its behavior in the kernel log
CAVEATS:
There are independent arrays for byte/data and word/data commands. Depending
on if/how a target driver mixes them, you'll need to be careful.
If your target driver polls some byte or word waiting for it to change, the
stub could lock it up. Use i2cset to unlock it.
If the hardware for your driver has banked registers (e.g. Winbond sensors
chips) this module will not work well - although it could be extended to
support that pretty easily.
If you spam it hard enough, printk can be lossy. This module really wants
something like relayfs.
......@@ -135,18 +135,44 @@ fan[1-3]_div Fan divisor.
Note that this is actually an internal clock divisor, which
affects the measurable speed range, not the read value.
fan[1-3]_pwm Pulse width modulation fan control.
*******
* PWM *
*******
pwm[1-3] Pulse width modulation fan control.
Integer value in the range 0 to 255
Read/Write
255 is max or 100%.
fan[1-3]_pwm_enable
pwm[1-3]_enable
Switch PWM on and off.
Not always present even if fan*_pwm is.
0 to turn off
1 to turn on
1 to turn on in manual mode
2 to turn on in automatic mode
Read/Write
pwm[1-*]_auto_channels_temp
Select which temperature channels affect this PWM output in
auto mode. Bitfield, 1 is temp1, 2 is temp2, 4 is temp3 etc...
Which values are possible depend on the chip used.
pwm[1-*]_auto_point[1-*]_pwm
pwm[1-*]_auto_point[1-*]_temp
pwm[1-*]_auto_point[1-*]_temp_hyst
Define the PWM vs temperature curve. Number of trip points is
chip-dependent. Use this for chips which associate trip points
to PWM output channels.
OR
temp[1-*]_auto_point[1-*]_pwm
temp[1-*]_auto_point[1-*]_temp
temp[1-*]_auto_point[1-*]_temp_hyst
Define the PWM vs temperature curve. Number of trip points is
chip-dependent. Use this for chips which associate trip points
to temperature channels.
****************
* Temperatures *
......
......@@ -24,22 +24,24 @@ all clients from it. Remember, a driver structure contains general access
routines, a client structure specific information like the actual I2C
address.
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 */
}
static struct i2c_driver foo_driver = {
.owner = THIS_MODULE,
.name = "Foo version 2.3 driver",
.id = I2C_DRIVERID_FOO, /* from i2c-id.h, optional */
.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
use something descriptive here.
The id should be a unique ID. The range 0xf000 to 0xffff is reserved for
local use, and you can use one of those until you start distributing the
driver. Before you do that, contact the i2c authors to get your own ID(s).
If used, the id should be a unique ID. The range 0xf000 to 0xffff is
reserved for local use, and you can use one of those until you start
distributing the driver, at which time you should contact the i2c authors
to get your own ID(s). Note that most of the time you don't need an ID
at all so you can just omit it.
Don't worry about the flags field; just put I2C_DF_NOTIFY into it. This
means that your driver will be notified when new adapters are found.
......
......@@ -107,14 +107,6 @@ static int wait_for_bb(struct i2c_algo_iic_data *adap)
return(timeout<=0);
}
/*
* Puts this process to sleep for a period equal to timeout
*/
static inline void iic_sleep(unsigned long timeout)
{
schedule_timeout( timeout * HZ);
}
/* After we issue a transaction on the IIC bus, this function
* is called. It puts this process to sleep until we get an interrupt from
* from the controller telling us that the transaction we requested in complete.
......
......@@ -40,21 +40,23 @@ config I2C_ALI15X3
will be called i2c-ali15x3.
config I2C_AMD756
tristate "AMD 756/766"
depends on I2C && EXPERIMENTAL
tristate "AMD 756/766/768/8111 and nVidia nForce"
depends on I2C && PCI && EXPERIMENTAL
help
If you say yes to this option, support will be included for the AMD
756/766/768 mainboard I2C interfaces.
756/766/768 mainboard I2C interfaces. The driver also includes
support for the first (SMBus 1.0) I2C interface of the AMD 8111 and
the nVidia nForce I2C interface.
This driver can also be built as a module. If so, the module
will be called i2c-amd756.
config I2C_AMD8111
tristate "AMD 8111"
depends on I2C && EXPERIMENTAL
depends on I2C && PCI && EXPERIMENTAL
help
If you say yes to this option, support will be included for the AMD
8111 mainboard I2C interfaces.
If you say yes to this option, support will be included for the
second (SMBus 2.0) AMD 8111 mainboard I2C interface.
This driver can also be built as a module. If so, the module
will be called i2c-amd8111.
......@@ -289,6 +291,13 @@ config I2C_RPXLITE
depends on (RPXLITE || RPXCLASSIC) && I2C
select I2C_ALGO8XX
config I2C_S3C2410
tristate "S3C2410 I2C Driver"
depends on I2C && ARCH_S3C2410
help
Say Y here to include support for I2C controller in the
Samsung S3C2410 based System-on-Chip devices.
config I2C_SAVAGE4
tristate "S3 Savage 4"
depends on I2C && PCI && EXPERIMENTAL
......@@ -376,6 +385,19 @@ config I2C_SIS96X
This driver can also be built as a module. If so, the module
will be called i2c-sis96x.
config I2C_STUB
tristate "I2C/SMBus Test Stub"
depends on I2C && EXPERIMENTAL && 'm'
default 'n'
help
This module may be useful to developers of SMBus client drivers,
especially for certain kinds of sensor chips.
If you do build this module, be sure to read the notes and warnings
in Documentation/i2c/i2c-stub.
If you don't know what to do here, definitely say N.
config I2C_VIA
tristate "VIA 82C586B"
depends on I2C && PCI && EXPERIMENTAL
......
......@@ -26,10 +26,12 @@ obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o
obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o
obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
obj-$(CONFIG_I2C_VIA) += i2c-via.o
obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
......
......@@ -496,6 +496,8 @@ static struct pci_device_id ali1535_ids[] = {
{ },
};
MODULE_DEVICE_TABLE (pci, ali1535_ids);
static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
if (ali1535_setup(dev)) {
......@@ -527,7 +529,7 @@ static struct pci_driver ali1535_driver = {
static int __init i2c_ali1535_init(void)
{
return pci_module_init(&ali1535_driver);
return pci_register_driver(&ali1535_driver);
}
static void __exit i2c_ali1535_exit(void)
......
......@@ -394,6 +394,8 @@ static struct pci_device_id __devinitdata ali1563_id_table[] = {
{},
};
MODULE_DEVICE_TABLE (pci, ali1563_id_table);
static struct pci_driver ali1563_pci_driver = {
.name = "ali1563_i2c",
.id_table = ali1563_id_table,
......@@ -403,7 +405,7 @@ static struct pci_driver ali1563_pci_driver = {
static int __init ali1563_init(void)
{
return pci_module_init(&ali1563_pci_driver);
return pci_register_driver(&ali1563_pci_driver);
}
module_init(ali1563_init);
......
......@@ -486,6 +486,8 @@ static struct pci_device_id ali15x3_ids[] = {
{ 0, }
};
MODULE_DEVICE_TABLE (pci, ali15x3_ids);
static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
if (ali15x3_setup(dev)) {
......@@ -517,7 +519,7 @@ static struct pci_driver ali15x3_driver = {
static int __init i2c_ali15x3_init(void)
{
return pci_module_init(&ali15x3_driver);
return pci_register_driver(&ali15x3_driver);
}
static void __exit i2c_ali15x3_exit(void)
......
......@@ -116,14 +116,14 @@ static int amd756_transaction(struct i2c_adapter *adap)
int result = 0;
int timeout = 0;
dev_dbg(&adap->dev, ": Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, "
dev_dbg(&adap->dev, "Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, "
"DAT=%04x\n", inw_p(SMB_GLOBAL_STATUS),
inw_p(SMB_GLOBAL_ENABLE), inw_p(SMB_HOST_ADDRESS),
inb_p(SMB_HOST_DATA));
/* Make sure the SMBus host is ready to start transmitting */
if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) {
dev_dbg(&adap->dev, ": SMBus busy (%04x). Waiting... \n", temp);
dev_dbg(&adap->dev, "SMBus busy (%04x). Waiting...\n", temp);
do {
msleep(1);
temp = inw_p(SMB_GLOBAL_STATUS);
......@@ -131,7 +131,7 @@ static int amd756_transaction(struct i2c_adapter *adap)
(timeout++ < MAX_TIMEOUT));
/* If the SMBus is still busy, we give up */
if (timeout >= MAX_TIMEOUT) {
dev_dbg(&adap->dev, ": Busy wait timeout (%04x)\n", temp);
dev_dbg(&adap->dev, "Busy wait timeout (%04x)\n", temp);
goto abort;
}
timeout = 0;
......@@ -148,46 +148,46 @@ static int amd756_transaction(struct i2c_adapter *adap)
/* If the SMBus is still busy, we give up */
if (timeout >= MAX_TIMEOUT) {
dev_dbg(&adap->dev, ": Completion timeout!\n");
dev_dbg(&adap->dev, "Completion timeout!\n");
goto abort;
}
if (temp & GS_PRERR_STS) {
result = -1;
dev_dbg(&adap->dev, ": SMBus Protocol error (no response)!\n");
dev_dbg(&adap->dev, "SMBus Protocol error (no response)!\n");
}
if (temp & GS_COL_STS) {
result = -1;
dev_warn(&adap->dev, " SMBus collision!\n");
dev_warn(&adap->dev, "SMBus collision!\n");
}
if (temp & GS_TO_STS) {
result = -1;
dev_dbg(&adap->dev, ": SMBus protocol timeout!\n");
dev_dbg(&adap->dev, "SMBus protocol timeout!\n");
}
if (temp & GS_HCYC_STS)
dev_dbg(&adap->dev, " SMBus protocol success!\n");
dev_dbg(&adap->dev, "SMBus protocol success!\n");
outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
#ifdef DEBUG
if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) {
dev_dbg(&adap->dev,
": Failed reset at end of transaction (%04x)\n", temp);
"Failed reset at end of transaction (%04x)\n", temp);
}
#endif
dev_dbg(&adap->dev,
": Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
"Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
return result;
abort:
dev_warn(&adap->dev, ": Sending abort.\n");
dev_warn(&adap->dev, "Sending abort\n");
outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE);
msleep(100);
outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
......@@ -204,7 +204,7 @@ static s32 amd756_access(struct i2c_adapter * adap, u16 addr,
/** TODO: Should I supporte the 10-bit transfers? */
switch (size) {
case I2C_SMBUS_PROC_CALL:
dev_dbg(&adap->dev, ": I2C_SMBUS_PROC_CALL not supported!\n");
dev_dbg(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
/* TODO: Well... It is supported, I'm just not sure what to do here... */
return -1;
case I2C_SMBUS_QUICK:
......@@ -310,6 +310,10 @@ static struct i2c_adapter amd756_adapter = {
};
enum chiptype { AMD756, AMD766, AMD768, NFORCE, AMD8111 };
static const char* chipname[] = {
"AMD756", "AMD766", "AMD768",
"nVidia nForce", "AMD8111",
};
static struct pci_device_id amd756_ids[] = {
{PCI_VENDOR_ID_AMD, 0x740B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD756 },
......@@ -320,6 +324,8 @@ static struct pci_device_id amd756_ids[] = {
{ 0, }
};
MODULE_DEVICE_TABLE (pci, amd756_ids);
static int __devinit amd756_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
......@@ -328,8 +334,8 @@ static int __devinit amd756_probe(struct pci_dev *pdev,
u8 temp;
if (amd756_ioport) {
dev_err(&pdev->dev, ": Only one device supported. "
"(you have a strange motherboard, btw..)\n");
dev_err(&pdev->dev, "Only one device supported "
"(you have a strange motherboard, btw)\n");
return -ENODEV;
}
......@@ -346,7 +352,7 @@ static int __devinit amd756_probe(struct pci_dev *pdev,
pci_read_config_byte(pdev, SMBGCFG, &temp);
if ((temp & 128) == 0) {
dev_err(&pdev->dev,
": Error: SMBus controller I/O not enabled!\n");
"Error: SMBus controller I/O not enabled!\n");
return -ENODEV;
}
......@@ -358,25 +364,25 @@ static int __devinit amd756_probe(struct pci_dev *pdev,
}
if (!request_region(amd756_ioport, SMB_IOSIZE, "amd756-smbus")) {
dev_err(&pdev->dev, ": SMB region 0x%x already in use!\n",
dev_err(&pdev->dev, "SMB region 0x%x already in use!\n",
amd756_ioport);
return -ENODEV;
}
pci_read_config_byte(pdev, SMBREV, &temp);
dev_dbg(&pdev->dev, ": SMBREV = 0x%X\n", temp);
dev_dbg(&pdev->dev, ": AMD756_smba = 0x%X\n", amd756_ioport);
dev_dbg(&pdev->dev, "SMBREV = 0x%X\n", temp);
dev_dbg(&pdev->dev, "AMD756_smba = 0x%X\n", amd756_ioport);
/* set up the driverfs linkage to our parent device */
amd756_adapter.dev.parent = &pdev->dev;
snprintf(amd756_adapter.name, I2C_NAME_SIZE,
"SMBus AMD756 adapter at %04x", amd756_ioport);
sprintf(amd756_adapter.name, "SMBus %s adapter at %04x",
chipname[id->driver_data], amd756_ioport);
error = i2c_add_adapter(&amd756_adapter);
if (error) {
dev_err(&pdev->dev,
": Adapter registration failed, module not inserted.\n");
"Adapter registration failed, module not inserted\n");
goto out_err;
}
......@@ -402,7 +408,7 @@ static struct pci_driver amd756_driver = {
static int __init amd756_init(void)
{
return pci_module_init(&amd756_driver);
return pci_register_driver(&amd756_driver);
}
static void __exit amd756_exit(void)
......
......@@ -336,6 +336,8 @@ static struct pci_device_id amd8111_ids[] = {
{ 0, }
};
MODULE_DEVICE_TABLE (pci, amd8111_ids);
static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
struct amd_smbus *smbus;
......@@ -400,7 +402,7 @@ static struct pci_driver amd8111_driver = {
static int __init i2c_amd8111_init(void)
{
return pci_module_init(&amd8111_driver);
return pci_register_driver(&amd8111_driver);
}
......
......@@ -180,11 +180,10 @@ static int __init i2c_pcfisa_init(void)
/* check to see we have memory mapped PCF8584 connected to the
Cypress cy82c693 PCI-ISA bridge as on UP2000 board */
if (base == 0) {
struct pci_dev *cy693_dev;
struct pci_dev *cy693_dev =
pci_find_device(PCI_VENDOR_ID_CONTAQ,
PCI_DEVICE_ID_CONTAQ_82C693, NULL);
cy693_dev = pci_get_device(PCI_VENDOR_ID_CONTAQ,
PCI_DEVICE_ID_CONTAQ_82C693, NULL);
if (cy693_dev) {
char config;
/* yeap, we've found cypress, let's check config */
......@@ -215,6 +214,7 @@ static int __init i2c_pcfisa_init(void)
printk(KERN_INFO "i2c-elektor: found API UP2000 like board, will probe PCF8584 later.\n");
}
}
pci_dev_put(cy693_dev);
}
}
#endif
......
......@@ -120,6 +120,8 @@ static struct pci_device_id hydra_ids[] = {
{ 0, }
};
MODULE_DEVICE_TABLE (pci, hydra_ids);
static int __devinit hydra_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
......@@ -166,7 +168,7 @@ static struct pci_driver hydra_driver = {
static int __init i2c_hydra_init(void)
{
return pci_module_init(&hydra_driver);
return pci_register_driver(&hydra_driver);
}
......
......@@ -599,6 +599,8 @@ static struct pci_device_id i801_ids[] = {
{ 0, }
};
MODULE_DEVICE_TABLE (pci, i801_ids);
static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
......@@ -631,7 +633,7 @@ static struct pci_driver i801_driver = {
static int __init i2c_i801_init(void)
{
return pci_module_init(&i801_driver);
return pci_register_driver(&i801_driver);
}
static void __exit i2c_i801_exit(void)
......
......@@ -70,7 +70,7 @@
#define CYCLE_DELAY 10
#define TIMEOUT (HZ / 2)
static void *ioaddr;
static void __iomem *ioaddr;
/* The i810 GPIO registers have individual masks for each bit
so we never have to read before writing. Nice. */
......@@ -201,6 +201,8 @@ static struct pci_device_id i810_ids[] __devinitdata = {
{ 0, },
};
MODULE_DEVICE_TABLE (pci, i810_ids);
static int __devinit i810_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int retval;
......@@ -239,7 +241,7 @@ static struct pci_driver i810_driver = {
static int __init i2c_i810_init(void)
{
return pci_module_init(&i810_driver);
return pci_register_driver(&i810_driver);
}
static void __exit i2c_i810_exit(void)
......
......@@ -416,10 +416,8 @@ static int iic_wait_for_tc(struct ibm_iic_private* dev){
init_waitqueue_entry(&wait, current);
add_wait_queue(&dev->wq, &wait);
set_current_state(TASK_INTERRUPTIBLE);
if (in_8(&iic->sts) & STS_PT)
schedule_timeout(dev->adap.timeout * HZ);
set_current_state(TASK_RUNNING);
msleep_interruptible(dev->adap.timeout * 1000);
remove_wait_queue(&dev->wq, &wait);
if (unlikely(signal_pending(current))){
......
......@@ -23,6 +23,7 @@
#include <asm/ocp.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#define MPC_I2C_ADDR 0x00
#define MPC_I2C_FDR 0x04
......@@ -91,9 +92,9 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
x = readb(i2c->base + MPC_I2C_SR);
writeb(0, i2c->base + MPC_I2C_SR);
} else {
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&i2c->queue, &wait);
while (!(i2c->interrupt & CSR_MIF)) {
set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) {
pr_debug("I2C: Interrupted\n");
result = -EINTR;
......@@ -104,9 +105,9 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
result = -EIO;
break;
}
schedule_timeout(timeout);
msleep_interruptible(jiffies_to_msecs(timeout));
}
current->state = TASK_RUNNING;
set_current_state(TASK_RUNNING);
remove_wait_queue(&i2c->queue, &wait);
x = i2c->interrupt;
i2c->interrupt = 0;
......
......@@ -298,6 +298,9 @@ static struct pci_device_id nforce2_ids[] = {
};
MODULE_DEVICE_TABLE (pci, nforce2_ids);
static int __devinit nforce2_probe_smb (struct pci_dev *dev, int reg,
struct nforce2_smbus *smbus, char *name)
{
......@@ -391,7 +394,7 @@ static struct pci_driver nforce2_driver = {
static int __init nforce2_init(void)
{
return pci_module_init(&nforce2_driver);
return pci_register_driver(&nforce2_driver);
}
static void __exit nforce2_exit(void)
......
......@@ -459,6 +459,8 @@ static struct pci_device_id piix4_ids[] = {
{ 0, }
};
MODULE_DEVICE_TABLE (pci, piix4_ids);
static int __devinit piix4_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
......@@ -501,7 +503,7 @@ static struct pci_driver piix4_driver = {
static int __init i2c_piix4_init(void)
{
return pci_module_init(&piix4_driver);
return pci_register_driver(&piix4_driver);
}
static void __exit i2c_piix4_exit(void)
......
......@@ -68,7 +68,7 @@
#define MAX_BUSSES 2
struct s_i2c_bus {
void *mmvga;
void __iomem *mmvga;
int i2c_reg;
int adap_ok;
struct i2c_adapter adap;
......@@ -76,7 +76,7 @@ struct s_i2c_bus {
};
struct s_i2c_chip {
void *mmio;
void __iomem *mmio;
struct s_i2c_bus i2c_bus[MAX_BUSSES];
};
......@@ -181,7 +181,7 @@ static int bit_s3via_getsda(void *bus)
/*
* adapter initialisation
*/
static int i2c_register_bus(struct pci_dev *dev, struct s_i2c_bus *p, u8 *mmvga, u32 i2c_reg)
static int i2c_register_bus(struct pci_dev *dev, struct s_i2c_bus *p, void __iomem *mmvga, u32 i2c_reg)
{
int ret;
p->adap.owner = THIS_MODULE;
......@@ -228,7 +228,7 @@ static void prosavage_remove(struct pci_dev *dev)
ret = i2c_bit_del_bus(&chip->i2c_bus[i].adap);
if (ret) {
dev_err(&dev->dev, ": %s not removed\n",
dev_err(&dev->dev, "%s not removed\n",
chip->i2c_bus[i].adap.name);
}
}
......@@ -298,7 +298,7 @@ static int __devinit prosavage_probe(struct pci_dev *dev, const struct pci_devic
}
return 0;
err_adap:
dev_err(&dev->dev, ": %s failed\n", bus->adap.name);
dev_err(&dev->dev, "%s failed\n", bus->adap.name);
prosavage_remove(dev);
return ret;
}
......@@ -313,6 +313,8 @@ static struct pci_device_id prosavage_pci_tbl[] = {
{ 0, },
};
MODULE_DEVICE_TABLE (pci, prosavage_pci_tbl);
static struct pci_driver prosavage_driver = {
.name = "prosavage_smbus",
.id_table = prosavage_pci_tbl,
......@@ -322,7 +324,7 @@ static struct pci_driver prosavage_driver = {
static int __init i2c_prosavage_init(void)
{
return pci_module_init(&prosavage_driver);
return pci_register_driver(&prosavage_driver);
}
static void __exit i2c_prosavage_exit(void)
......
/* linux/drivers/i2c/busses/i2c-s3c2410.c
*
* Copyright (C) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 I2C Controller
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/device.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/hardware/clock.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-iic.h>
#include <asm/arch/iic.h>
/* i2c controller state */
enum s3c24xx_i2c_state {
STATE_IDLE,
STATE_START,
STATE_READ,
STATE_WRITE,
STATE_STOP
};
struct s3c24xx_i2c {
spinlock_t lock;
wait_queue_head_t wait;
struct i2c_msg *msg;
unsigned int msg_num;
unsigned int msg_idx;
unsigned int msg_ptr;
enum s3c24xx_i2c_state state;
void __iomem *regs;
struct clk *clk;
struct device *dev;
struct resource *irq;
struct resource *ioarea;
struct i2c_adapter adap;
};
/* default platform data to use if not supplied in the platfrom_device
*/
static struct s3c2410_platform_i2c s3c24xx_i2c_default_platform = {
.flags = 0,
.slave_addr = 0x10,
.bus_freq = 100*1000,
.max_freq = 400*1000,
};
/* s3c24xx_i2c_get_platformdata
*
* get the platform data associated with the given device, or return
* the default if there is none
*/
static inline struct s3c2410_platform_i2c *s3c24xx_i2c_get_platformdata(struct device *dev)
{
if (dev->platform_data != NULL)
return (struct s3c2410_platform_i2c *)dev->platform_data;
return &s3c24xx_i2c_default_platform;
}
/* s3c24xx_i2c_master_complete
*
* complete the message and wake up the caller, using the given return code,
* or zero to mean ok.
*/
static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret)
{
dev_dbg(i2c->dev, "master_complete %d\n", ret);
i2c->msg_ptr = 0;
i2c->msg = NULL;
i2c->msg_idx ++;
i2c->msg_num = 0;
if (ret)
i2c->msg_idx = ret;
wake_up(&i2c->wait);
}
static inline void s3c24xx_i2c_disable_ack(struct s3c24xx_i2c *i2c)
{
unsigned long tmp;
tmp = readl(i2c->regs + S3C2410_IICCON);
writel(tmp & ~S3C2410_IICCON_ACKEN, i2c->regs + S3C2410_IICCON);
}
static inline void s3c24xx_i2c_enable_ack(struct s3c24xx_i2c *i2c)
{
unsigned long tmp;
tmp = readl(i2c->regs + S3C2410_IICCON);
writel(tmp | S3C2410_IICCON_ACKEN, i2c->regs + S3C2410_IICCON);
}
/* irq enable/disable functions */
static inline void s3c24xx_i2c_disable_irq(struct s3c24xx_i2c *i2c)
{
unsigned long tmp;
tmp = readl(i2c->regs + S3C2410_IICCON);
writel(tmp & ~S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON);
}
static inline void s3c24xx_i2c_enable_irq(struct s3c24xx_i2c *i2c)
{
unsigned long tmp;
tmp = readl(i2c->regs + S3C2410_IICCON);
writel(tmp | S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON);
}
/* s3c24xx_i2c_message_start
*
* put the start of a message onto the bus
*/
static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
struct i2c_msg *msg)
{
unsigned int addr = (msg->addr & 0x7f) << 1;
unsigned long stat;
stat = readl(i2c->regs + S3C2410_IICSTAT);
stat &= ~S3C2410_IICSTAT_MODEMASK;
stat |= S3C2410_IICSTAT_START;
stat |= S3C2410_IICSTAT_TXRXEN;
if (msg->flags & I2C_M_RD) {
stat |= S3C2410_IICSTAT_MASTER_RX;
addr |= 1;
} else
stat |= S3C2410_IICSTAT_MASTER_TX;
// todo - check for wether ack wanted or not
s3c24xx_i2c_enable_ack(i2c);
dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);
writeb(addr, i2c->regs + S3C2410_IICDS);
writel(stat, i2c->regs + S3C2410_IICSTAT);
}
static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
{
unsigned long iicstat = readl(i2c->regs + S3C2410_IICSTAT);
dev_dbg(i2c->dev, "STOP\n");
/* stop the transfer */
iicstat &= ~ S3C2410_IICSTAT_START;
writel(iicstat, i2c->regs + S3C2410_IICSTAT);
i2c->state = STATE_STOP;
s3c24xx_i2c_master_complete(i2c, ret);
s3c24xx_i2c_disable_irq(i2c);
}
/* helper functions to determine the current state in the set of
* messages we are sending */
/* is_lastmsg()
*
* returns TRUE if the current message is the last in the set
*/
static inline int is_lastmsg(struct s3c24xx_i2c *i2c)
{
return i2c->msg_idx >= (i2c->msg_num - 1);
}
/* is_msglast
*
* returns TRUE if we this is the last byte in the current message
*/
static inline int is_msglast(struct s3c24xx_i2c *i2c)
{
return i2c->msg_ptr == i2c->msg->len-1;
}
/* is_msgend
*
* returns TRUE if we reached the end of the current message
*/
static inline int is_msgend(struct s3c24xx_i2c *i2c)
{
return i2c->msg_ptr >= i2c->msg->len;
}
/* i2s_s3c_irq_nextbyte
*
* process an interrupt and work out what to do
*/
static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
{
unsigned long tmp;
unsigned char byte;
int ret = 0;
switch (i2c->state) {
case STATE_IDLE:
dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __FUNCTION__);
goto out;
break;
case STATE_STOP:
dev_err(i2c->dev, "%s: called in STATE_STOP\n", __FUNCTION__);
s3c24xx_i2c_disable_irq(i2c);
goto out_ack;
case STATE_START:
/* last thing we did was send a start condition on the
* bus, or started a new i2c message
*/
if (iicstat & S3C2410_IICSTAT_LASTBIT &&
!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
/* ack was not received... */
s3c24xx_i2c_stop(i2c, -EREMOTEIO);
goto out_ack;
}
if (i2c->msg->flags & I2C_M_RD)
i2c->state = STATE_READ;
else
i2c->state = STATE_WRITE;
/* terminate the transfer if there is nothing to do
* (used by the i2c probe to find devices */
if (is_lastmsg(i2c) && i2c->msg->len == 0) {
s3c24xx_i2c_stop(i2c, 0);
goto out_ack;
}
if (i2c->state == STATE_READ)
goto prepare_read;
/* fall through to the write state, as we will need to
* send a byte as well */
case STATE_WRITE:
/* we are writing data to the device... check for the
* end of the message, and if so, work out what to do
*/
retry_write:
if (!is_msgend(i2c)) {
byte = i2c->msg->buf[i2c->msg_ptr++];
writeb(byte, i2c->regs + S3C2410_IICDS);
} else if (!is_lastmsg(i2c)) {
/* we need to go to the next i2c message */
dev_dbg(i2c->dev, "WRITE: Next Message\n");
i2c->msg_ptr = 0;
i2c->msg_idx ++;
i2c->msg++;
/* check to see if we need to do another message */
if (i2c->msg->flags & I2C_M_NOSTART) {
if (i2c->msg->flags & I2C_M_RD) {
/* cannot do this, the controller
* forces us to send a new START
* when we change direction */
s3c24xx_i2c_stop(i2c, -EINVAL);
}
goto retry_write;
} else {
/* send the new start */
s3c24xx_i2c_message_start(i2c, i2c->msg);
i2c->state = STATE_START;
}
} else {
/* send stop */
s3c24xx_i2c_stop(i2c, 0);
}
break;
case STATE_READ:
/* we have a byte of data in the data register, do
* something with it, and then work out wether we are
* going to do any more read/write
*/
if (!(i2c->msg->flags & I2C_M_IGNORE_NAK) &&
!(is_msglast(i2c) && is_lastmsg(i2c))) {
if (iicstat & S3C2410_IICSTAT_LASTBIT) {
dev_dbg(i2c->dev, "READ: No Ack\n");
s3c24xx_i2c_stop(i2c, -ECONNREFUSED);
goto out_ack;
}
}
byte = readb(i2c->regs + S3C2410_IICDS);
i2c->msg->buf[i2c->msg_ptr++] = byte;
prepare_read:
if (is_msglast(i2c)) {
/* last byte of buffer */
if (is_lastmsg(i2c))
s3c24xx_i2c_disable_ack(i2c);
} else if (is_msgend(i2c)) {
/* ok, we've read the entire buffer, see if there
* is anything else we need to do */
if (is_lastmsg(i2c)) {
/* last message, send stop and complete */
dev_dbg(i2c->dev, "READ: Send Stop\n");
s3c24xx_i2c_stop(i2c, 0);
} else {
/* go to the next transfer */
dev_dbg(i2c->dev, "READ: Next Transfer\n");
i2c->msg_ptr = 0;
i2c->msg_idx++;
i2c->msg++;
}
}
break;
}
/* acknowlegde the IRQ and get back on with the work */
out_ack:
tmp = readl(i2c->regs + S3C2410_IICCON);
tmp &= ~S3C2410_IICCON_IRQPEND;
writel(tmp, i2c->regs + S3C2410_IICCON);
out:
return ret;
}
/* s3c24xx_i2c_irq
*
* top level IRQ servicing routine
*/
static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id,
struct pt_regs *regs)
{
struct s3c24xx_i2c *i2c = dev_id;
unsigned long status;
unsigned long tmp;
status = readl(i2c->regs + S3C2410_IICSTAT);
if (status & S3C2410_IICSTAT_ARBITR) {
// deal with arbitration loss
}
if (i2c->state == STATE_IDLE) {
dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n");
tmp = readl(i2c->regs + S3C2410_IICCON);
tmp &= ~S3C2410_IICCON_IRQPEND;
writel(tmp, i2c->regs + S3C2410_IICCON);
goto out;
}
/* pretty much this leaves us with the fact that we've
* transmitted or received whatever byte we last sent */
i2s_s3c_irq_nextbyte(i2c, status);
out:
return IRQ_HANDLED;
}
/* s3c24xx_i2c_set_master
*
* get the i2c bus for a master transaction
*/
static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
{
unsigned long iicstat;
int timeout = 400;
while (timeout-- > 0) {
iicstat = readl(i2c->regs + S3C2410_IICSTAT);
if (!(iicstat & S3C2410_IICSTAT_BUSBUSY))
return 0;
msleep(1);
}
dev_dbg(i2c->dev, "timeout: GPEDAT is %08x\n",
__raw_readl(S3C2410_GPEDAT));
return -ETIMEDOUT;
}
/* s3c24xx_i2c_doxfer
*
* this starts an i2c transfer
*/
static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg msgs[], int num)
{
unsigned long timeout;
int ret;
ret = s3c24xx_i2c_set_master(i2c);
if (ret != 0) {
dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);
ret = -EAGAIN;
goto out;
}
spin_lock_irq(&i2c->lock);
i2c->msg = msgs;
i2c->msg_num = num;
i2c->msg_ptr = 0;
i2c->msg_idx = 0;
i2c->state = STATE_START;
s3c24xx_i2c_enable_irq(i2c);
s3c24xx_i2c_message_start(i2c, msgs);
spin_unlock_irq(&i2c->lock);
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
ret = i2c->msg_idx;
/* having these next two as dev_err() makes life very
* noisy when doing an i2cdetect */
if (timeout == 0)
dev_dbg(i2c->dev, "timeout\n");
else if (ret != num)
dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
/* ensure the stop has been through the bus */
msleep(1);
out:
return ret;
}
/* s3c24xx_i2c_xfer
*
* first port of call from the i2c bus code when an message needs
* transfering across the i2c bus.
*/
static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg msgs[], int num)
{
struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;
int retry;
int ret;
for (retry = 0; retry < adap->retries; retry++) {
ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
if (ret != -EAGAIN)
return ret;
dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);
udelay(100);
}
return -EREMOTEIO;
}
/* i2c bus registration info */
static struct i2c_algorithm s3c24xx_i2c_algorithm = {
.name = "S3C2410-I2C-Algorithm",
.id = I2C_ALGO_S3C2410,
.master_xfer = s3c24xx_i2c_xfer,
};
static struct s3c24xx_i2c s3c24xx_i2c = {
.lock = SPIN_LOCK_UNLOCKED,
.wait = __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait),
.adap = {
.name = "s3c2410-i2c",
.id = I2C_ALGO_S3C2410,
.algo = &s3c24xx_i2c_algorithm,
.retries = 2,
},
};
/* s3c24xx_i2c_calcdivisor
*
* return the divisor settings for a given frequency
*/
static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted,
unsigned int *div1, unsigned int *divs)
{
unsigned int calc_divs = clkin / wanted;
unsigned int calc_div1;
if (calc_divs > (16*16))
calc_div1 = 512;
else
calc_div1 = 16;
calc_divs += calc_div1-1;
calc_divs /= calc_div1;
if (calc_divs == 0)
calc_divs = 1;
if (calc_divs > 17)
calc_divs = 17;
*divs = calc_divs;
*div1 = calc_div1;
return clkin / (calc_divs + calc_div1);
}
/* freq_acceptable
*
* test wether a frequency is within the acceptable range of error
*/
static inline int freq_acceptable(unsigned int freq, unsigned int wanted)
{
int diff = freq - wanted;
return (diff >= -2 && diff <= 2);
}
/* s3c24xx_i2c_getdivisor
*
* work out a divisor for the user requested frequency setting,
* either by the requested frequency, or scanning the acceptable
* range of frequencies until something is found
*/
static int s3c24xx_i2c_getdivisor(struct s3c24xx_i2c *i2c,
struct s3c2410_platform_i2c *pdata,
unsigned long *iicon,
unsigned int *got)
{
unsigned long clkin = clk_get_rate(i2c->clk);
unsigned int divs, div1;
int freq;
int start, end;
clkin /= 1000; /* clkin now in KHz */
dev_dbg(i2c->dev, "pdata %p, freq %lu %lu..%lu\n",
pdata, pdata->bus_freq, pdata->min_freq, pdata->max_freq);
if (pdata->bus_freq != 0) {
freq = s3c24xx_i2c_calcdivisor(clkin, pdata->bus_freq/1000,
&div1, &divs);
if (freq_acceptable(freq, pdata->bus_freq/1000))
goto found;
}
/* ok, we may have to search for something suitable... */
start = (pdata->max_freq == 0) ? pdata->bus_freq : pdata->max_freq;
end = pdata->min_freq;
start /= 1000;
end /= 1000;
/* search loop... */
for (; start > end; start--) {
freq = s3c24xx_i2c_calcdivisor(clkin, start, &div1, &divs);
if (freq_acceptable(freq, start))
goto found;
}
/* cannot find frequency spec */
return -EINVAL;
found:
*got = freq;
*iicon |= (divs-1);
*iicon |= (div1 == 512) ? S3C2410_IICCON_TXDIV_512 : 0;
return 0;
}
/* s3c24xx_i2c_init
*
* initialise the controller, set the IO lines and frequency
*/
static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
{
unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN;
struct s3c2410_platform_i2c *pdata;
unsigned int freq;
/* get the plafrom data */
pdata = s3c24xx_i2c_get_platformdata(i2c->adap.dev.parent);
/* inititalise the gpio */
s3c2410_gpio_cfgpin(S3C2410_GPE15, S3C2410_GPE15_IICSDA);
s3c2410_gpio_cfgpin(S3C2410_GPE14, S3C2410_GPE14_IICSCL);
/* write slave address */
writeb(pdata->slave_addr, i2c->regs + S3C2410_IICADD);
dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);
/* we need to work out the divisors for the clock... */
if (s3c24xx_i2c_getdivisor(i2c, pdata, &iicon, &freq) != 0) {
dev_err(i2c->dev, "cannot meet bus frequency required\n");
return -EINVAL;
}
/* todo - check that the i2c lines aren't being dragged anywhere */
dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq);
return 0;
}
static void s3c24xx_i2c_free(struct s3c24xx_i2c *i2c)
{
if (i2c->clk != NULL && !IS_ERR(i2c->clk)) {
clk_disable(i2c->clk);
clk_unuse(i2c->clk);
clk_put(i2c->clk);
i2c->clk = NULL;
}
if (i2c->regs != NULL) {
iounmap(i2c->regs);
i2c->regs = NULL;
}
if (i2c->ioarea != NULL) {
release_resource(i2c->ioarea);
kfree(i2c->ioarea);
i2c->ioarea = NULL;
}
}
/* s3c24xx_i2c_probe
*
* called by the bus driver when a suitable device is found
*/
static int s3c24xx_i2c_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct s3c24xx_i2c *i2c = &s3c24xx_i2c;
struct resource *res;
int ret;
/* find the clock and enable it */
i2c->dev = dev;
i2c->clk = clk_get(dev, "i2c");
if (IS_ERR(i2c->clk)) {
dev_err(dev, "cannot get clock\n");
ret = -ENOENT;
goto out;
}
dev_dbg(dev, "clock source %p\n", i2c->clk);
clk_use(i2c->clk);
clk_enable(i2c->clk);
/* map the registers */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
dev_err(dev, "cannot find IO resource\n");
ret = -ENOENT;
goto out;
}
i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1,
pdev->name);
if (i2c->ioarea == NULL) {
dev_err(dev, "cannot request IO\n");
ret = -ENXIO;
goto out;
}
i2c->regs = ioremap(res->start, (res->end-res->start)+1);
if (i2c->regs == NULL) {
dev_err(dev, "cannot map IO\n");
ret = -ENXIO;
goto out;
}
dev_dbg(dev, "registers %p (%p, %p)\n", i2c->regs, i2c->ioarea, res);
/* setup info block for the i2c core */
i2c->adap.algo_data = i2c;
i2c->adap.dev.parent = dev;
/* initialise the i2c controller */
ret = s3c24xx_i2c_init(i2c);
if (ret != 0)
goto out;
/* find the IRQ for this unit (note, this relies on the init call to
* ensure no current IRQs pending
*/
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
dev_err(dev, "cannot find IRQ\n");
ret = -ENOENT;
goto out;
}
ret = request_irq(res->start, s3c24xx_i2c_irq, SA_INTERRUPT,
pdev->name, i2c);
if (ret != 0) {
dev_err(dev, "cannot claim IRQ\n");
goto out;
}
i2c->irq = res;
dev_dbg(dev, "irq resource %p (%ld)\n", res, res->start);
ret = i2c_add_adapter(&i2c->adap);
if (ret < 0) {
dev_err(dev, "failed to add bus to i2c core\n");
goto out;
}
dev_set_drvdata(dev, i2c);
dev_info(dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id);
out:
if (ret < 0)
s3c24xx_i2c_free(i2c);
return ret;
}
/* s3c24xx_i2c_remove
*
* called when device is removed from the bus
*/
static int s3c24xx_i2c_remove(struct device *dev)
{
struct s3c24xx_i2c *i2c = dev_get_drvdata(dev);
if (i2c != NULL) {
s3c24xx_i2c_free(i2c);
dev_set_drvdata(dev, NULL);
}
return 0;
}
#ifdef CONFIG_PM
static int s3c24xx_i2c_resume(struct device *dev, u32 level)
{
struct s3c24xx_i2c *i2c = dev_get_drvdata(dev);
if (i2c != NULL && level == RESUME_ENABLE) {
dev_dbg(dev, "resume: level %d\n", level);
s3c24xx_i2c_init(i2c);
}
return 0;
}
#else
#define s3c24xx_i2c_resume NULL
#endif
/* device driver for platform bus bits */
static struct device_driver s3c24xx_i2c_driver = {
.name = "s3c2410-i2c",
.bus = &platform_bus_type,
.probe = s3c24xx_i2c_probe,
.remove = s3c24xx_i2c_remove,
.resume = s3c24xx_i2c_resume,
};
static int __init i2c_adap_s3c_init(void)
{
return driver_register(&s3c24xx_i2c_driver);
}
static void i2c_adap_s3c_exit(void)
{
return driver_unregister(&s3c24xx_i2c_driver);
}
module_init(i2c_adap_s3c_init);
module_exit(i2c_adap_s3c_exit);
MODULE_DESCRIPTION("S3C24XX I2C Bus driver");
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_LICENSE("GPL");
......@@ -73,7 +73,7 @@
#define TIMEOUT (HZ / 2)
static void *ioaddr;
static void __iomem *ioaddr;
/* The sav GPIO registers don't have individual masks for each bit
so we always have to read before writing. */
......@@ -157,6 +157,8 @@ static struct pci_device_id savage4_ids[] __devinitdata = {
{ 0, }
};
MODULE_DEVICE_TABLE (pci, savage4_ids);
static int __devinit savage4_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int retval;
......@@ -186,7 +188,7 @@ static struct pci_driver savage4_driver = {
static int __init i2c_savage4_init(void)
{
return pci_module_init(&savage4_driver);
return pci_register_driver(&savage4_driver);
}
static void __exit i2c_savage4_exit(void)
......
......@@ -371,6 +371,8 @@ static struct pci_device_id sis5595_ids[] __devinitdata = {
{ 0, }
};
MODULE_DEVICE_TABLE (pci, sis5595_ids);
static int __devinit sis5595_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
if (sis5595_setup(dev)) {
......@@ -401,7 +403,7 @@ static struct pci_driver sis5595_driver = {
static int __init i2c_sis5595_init(void)
{
return pci_module_init(&sis5595_driver);
return pci_register_driver(&sis5595_driver);
}
static void __exit i2c_sis5595_exit(void)
......
......@@ -468,6 +468,8 @@ static struct pci_device_id sis630_ids[] __devinitdata = {
{ 0, }
};
MODULE_DEVICE_TABLE (pci, sis630_ids);
static int __devinit sis630_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
if (sis630_setup(dev)) {
......@@ -503,7 +505,7 @@ static struct pci_driver sis630_driver = {
static int __init i2c_sis630_init(void)
{
return pci_module_init(&sis630_driver);
return pci_register_driver(&sis630_driver);
}
......
......@@ -278,6 +278,8 @@ static struct pci_device_id sis96x_ids[] = {
{ 0, }
};
MODULE_DEVICE_TABLE (pci, sis96x_ids);
static int __devinit sis96x_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
......@@ -348,7 +350,7 @@ static struct pci_driver sis96x_driver = {
static int __init i2c_sis96x_init(void)
{
printk(KERN_INFO "i2c-sis96x version %s\n", SIS96x_VERSION);
return pci_module_init(&sis96x_driver);
return pci_register_driver(&sis96x_driver);
}
static void __exit i2c_sis96x_exit(void)
......
/*
i2c-stub.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (c) 2004 Mark M. Hoffman <mhoffman@lightlink.com>
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 <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/i2c.h>
static u8 stub_bytes[256];
static u16 stub_words[256];
/* Return -1 on error. */
static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
char read_write, u8 command, int size, union i2c_smbus_data * data)
{
s32 ret;
switch (size) {
case I2C_SMBUS_QUICK:
dev_dbg(&adap->dev, "smbus quick - addr 0x%02x\n", addr);
ret = 0;
break;
case I2C_SMBUS_BYTE_DATA:
if (read_write == I2C_SMBUS_WRITE) {
stub_bytes[command] = data->byte;
dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
"wrote 0x%02x at 0x%02x.\n",
addr, data->byte, command);
} else {
data->byte = stub_bytes[command];
dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
"read 0x%02x at 0x%02x.\n",
addr, data->byte, command);
}
ret = 0;
break;
case I2C_SMBUS_WORD_DATA:
if (read_write == I2C_SMBUS_WRITE) {
stub_words[command] = data->word;
dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
"wrote 0x%04x at 0x%02x.\n",
addr, data->word, command);
} else {
data->word = stub_words[command];
dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
"read 0x%04x at 0x%02x.\n",
addr, data->word, command);
}
ret = 0;
break;
default:
dev_dbg(&adap->dev, "Unsupported I2C/SMBus command\n");
ret = -1;
break;
} /* switch (size) */
return ret;
}
static u32 stub_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA;
}
static struct i2c_algorithm smbus_algorithm = {
.name = "Non-I2C SMBus adapter",
.id = I2C_ALGO_SMBUS,
.functionality = stub_func,
.smbus_xfer = stub_xfer,
};
static struct i2c_adapter stub_adapter = {
.owner = THIS_MODULE,
.class = I2C_CLASS_HWMON,
.algo = &smbus_algorithm,
.name = "SMBus stub driver",
};
static int __init i2c_stub_init(void)
{
printk(KERN_INFO "i2c-stub loaded\n");
return i2c_add_adapter(&stub_adapter);
}
static void __exit i2c_stub_exit(void)
{
i2c_del_adapter(&stub_adapter);
}
MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
MODULE_DESCRIPTION("I2C stub driver");
MODULE_LICENSE("GPL");
module_init(i2c_stub_init);
module_exit(i2c_stub_exit);
......@@ -99,6 +99,8 @@ static struct pci_device_id vt586b_ids[] __devinitdata = {
{ 0, }
};
MODULE_DEVICE_TABLE (pci, vt586b_ids);
static int __devinit vt586b_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
u16 base;
......@@ -166,7 +168,7 @@ static struct pci_driver vt586b_driver = {
static int __init i2c_vt586b_init(void)
{
return pci_module_init(&vt586b_driver);
return pci_register_driver(&vt586b_driver);
}
static void __exit i2c_vt586b_exit(void)
......
......@@ -454,6 +454,8 @@ static struct pci_device_id vt596_ids[] = {
{ 0, }
};
MODULE_DEVICE_TABLE (pci, vt596_ids);
static struct pci_driver vt596_driver = {
.name = "vt596_smbus",
.id_table = vt596_ids,
......@@ -463,7 +465,7 @@ static struct pci_driver vt596_driver = {
static int __init i2c_vt596_init(void)
{
return pci_module_init(&vt596_driver);
return pci_register_driver(&vt596_driver);
}
......
......@@ -61,7 +61,7 @@
#define TIMEOUT (HZ / 2)
static void *ioaddr;
static void __iomem *ioaddr;
/* The voo GPIO registers don't have individual masks for each bit
so we always have to read before writing. */
......@@ -195,6 +195,8 @@ static struct pci_device_id voodoo3_ids[] __devinitdata = {
{ 0, }
};
MODULE_DEVICE_TABLE (pci, voodoo3_ids);
static int __devinit voodoo3_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int retval;
......@@ -232,7 +234,7 @@ static struct pci_driver voodoo3_driver = {
static int __init i2c_voodoo3_init(void)
{
return pci_module_init(&voodoo3_driver);
return pci_register_driver(&voodoo3_driver);
}
static void __exit i2c_voodoo3_exit(void)
......
......@@ -503,6 +503,12 @@ static int __init scx200_acb_create(int base, int index)
return rc;
}
static struct pci_device_id scx200[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
{ },
};
static int __init scx200_acb_init(void)
{
int i;
......@@ -511,12 +517,7 @@ static int __init scx200_acb_init(void)
pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
/* Verify that this really is a SCx200 processor */
if (pci_find_device(PCI_VENDOR_ID_NS,
PCI_DEVICE_ID_NS_SCx200_BRIDGE,
NULL) == NULL
&& pci_find_device(PCI_VENDOR_ID_NS,
PCI_DEVICE_ID_NS_SC1100_BRIDGE,
NULL) == NULL)
if (pci_dev_present(scx200) == 0)
return -ENODEV;
rc = -ENXIO;
......
......@@ -169,6 +169,17 @@ config SENSORS_LM85
This driver can also be built as a module. If so, the module
will be called lm85.
config SENSORS_LM87
tristate "National Semiconductor LM87"
depends on I2C && EXPERIMENTAL
select I2C_SENSOR
help
If you say yes here you get support for National Semiconductor LM87
sensor chips.
This driver can also be built as a module. If so, the module
will be called lm87.
config SENSORS_LM90
tristate "National Semiconductor LM90 and compatibles"
depends on I2C
......
......@@ -21,6 +21,7 @@ obj-$(CONFIG_SENSORS_LM78) += lm78.o
obj-$(CONFIG_SENSORS_LM80) += lm80.o
obj-$(CONFIG_SENSORS_LM83) += lm83.o
obj-$(CONFIG_SENSORS_LM85) += lm85.o
obj-$(CONFIG_SENSORS_LM87) += lm87.o
obj-$(CONFIG_SENSORS_LM90) += lm90.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
......
......@@ -148,7 +148,7 @@ static struct i2c_driver adm1021_driver = {
.detach_client = adm1021_detach_client,
};
static int adm1021_id = 0;
static int adm1021_id;
#define show(value) \
static ssize_t show_##value(struct device *dev, char *buf) \
......
......@@ -153,7 +153,7 @@ struct adm1025_data {
* Internal variables
*/
static int adm1025_id = 0;
static int adm1025_id;
/*
* Sysfs stuff
......@@ -212,8 +212,8 @@ static ssize_t set_in##offset##_min(struct device *dev, const char *buf, \
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct adm1025_data *data = i2c_get_clientdata(client); \
data->in_min[offset] = IN_TO_REG(simple_strtol(buf, NULL, 10), \
in_scale[offset]); \
long val = simple_strtol(buf, NULL, 10); \
data->in_min[offset] = IN_TO_REG(val, in_scale[offset]); \
i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(offset), \
data->in_min[offset]); \
return count; \
......@@ -223,8 +223,8 @@ static ssize_t set_in##offset##_max(struct device *dev, const char *buf, \
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct adm1025_data *data = i2c_get_clientdata(client); \
data->in_max[offset] = IN_TO_REG(simple_strtol(buf, NULL, 10), \
in_scale[offset]); \
long val = simple_strtol(buf, NULL, 10); \
data->in_max[offset] = IN_TO_REG(val, in_scale[offset]); \
i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(offset), \
data->in_max[offset]); \
return count; \
......@@ -246,7 +246,8 @@ static ssize_t set_temp##offset##_min(struct device *dev, const char *buf, \
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct adm1025_data *data = i2c_get_clientdata(client); \
data->temp_min[offset-1] = TEMP_TO_REG(simple_strtol(buf, NULL, 10)); \
long val = simple_strtol(buf, NULL, 10); \
data->temp_min[offset-1] = TEMP_TO_REG(val); \
i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(offset-1), \
data->temp_min[offset-1]); \
return count; \
......@@ -256,7 +257,8 @@ static ssize_t set_temp##offset##_max(struct device *dev, const char *buf, \
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct adm1025_data *data = i2c_get_clientdata(client); \
data->temp_max[offset-1] = TEMP_TO_REG(simple_strtol(buf, NULL, 10)); \
long val = simple_strtol(buf, NULL, 10); \
data->temp_max[offset-1] = TEMP_TO_REG(val); \
i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(offset-1), \
data->temp_max[offset-1]); \
return count; \
......
......@@ -298,12 +298,12 @@ set_fan_auto_channel(struct device *dev, const char *buf, size_t count, int nr)
#define fan_auto_channel_offset(offset) \
static ssize_t show_fan_auto_channel_##offset (struct device *dev, char *buf) \
{ \
return show_fan_auto_channel(dev, buf, 0x##offset - 1); \
return show_fan_auto_channel(dev, buf, offset - 1); \
} \
static ssize_t set_fan_auto_channel_##offset (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_fan_auto_channel(dev, buf, count, 0x##offset - 1); \
return set_fan_auto_channel(dev, buf, count, offset - 1); \
} \
static DEVICE_ATTR(auto_fan##offset##_channel, S_IRUGO | S_IWUSR, \
show_fan_auto_channel_##offset, \
......@@ -365,25 +365,25 @@ set_auto_temp_max(struct device *dev, const char *buf, size_t count, int nr)
#define auto_temp_reg(offset) \
static ssize_t show_auto_temp_##offset##_off (struct device *dev, char *buf) \
{ \
return show_auto_temp_off(dev, buf, 0x##offset - 1); \
return show_auto_temp_off(dev, buf, offset - 1); \
} \
static ssize_t show_auto_temp_##offset##_min (struct device *dev, char *buf) \
{ \
return show_auto_temp_min(dev, buf, 0x##offset - 1); \
return show_auto_temp_min(dev, buf, offset - 1); \
} \
static ssize_t show_auto_temp_##offset##_max (struct device *dev, char *buf) \
{ \
return show_auto_temp_max(dev, buf, 0x##offset - 1); \
return show_auto_temp_max(dev, buf, offset - 1); \
} \
static ssize_t set_auto_temp_##offset##_min (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_auto_temp_min(dev, buf, count, 0x##offset - 1); \
return set_auto_temp_min(dev, buf, count, offset - 1); \
} \
static ssize_t set_auto_temp_##offset##_max (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_auto_temp_max(dev, buf, count, 0x##offset - 1); \
return set_auto_temp_max(dev, buf, count, offset - 1); \
} \
static DEVICE_ATTR(auto_temp##offset##_off, S_IRUGO, \
show_auto_temp_##offset##_off, NULL); \
......@@ -429,14 +429,14 @@ set_pwm(struct device *dev, const char *buf, size_t count, int nr)
#define pwm_reg(offset) \
static ssize_t show_pwm_##offset (struct device *dev, char *buf) \
{ \
return show_pwm(dev, buf, 0x##offset - 1); \
return show_pwm(dev, buf, offset - 1); \
} \
static ssize_t set_pwm_##offset (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_pwm(dev, buf, count, 0x##offset - 1); \
return set_pwm(dev, buf, count, offset - 1); \
} \
static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, \
static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
show_pwm_##offset, set_pwm_##offset)
pwm_reg(1);
......@@ -565,25 +565,25 @@ set_fan_div(struct device *dev, const char *buf, size_t count, int nr)
#define fan_offset(offset) \
static ssize_t show_fan_##offset (struct device *dev, char *buf) \
{ \
return show_fan(dev, buf, 0x##offset - 1); \
return show_fan(dev, buf, offset - 1); \
} \
static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \
{ \
return show_fan_min(dev, buf, 0x##offset - 1); \
return show_fan_min(dev, buf, offset - 1); \
} \
static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \
{ \
return show_fan_div(dev, buf, 0x##offset - 1); \
return show_fan_div(dev, buf, offset - 1); \
} \
static ssize_t set_fan_##offset##_min (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_fan_min(dev, buf, count, 0x##offset - 1); \
return set_fan_min(dev, buf, count, offset - 1); \
} \
static ssize_t set_fan_##offset##_div (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_fan_div(dev, buf, count, 0x##offset - 1); \
return set_fan_div(dev, buf, count, offset - 1); \
} \
static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, \
NULL); \
......@@ -675,34 +675,34 @@ set_temp_crit(struct device *dev, const char *buf, size_t count, int nr)
#define temp_reg(offset) \
static ssize_t show_temp_##offset (struct device *dev, char *buf) \
{ \
return show_temp(dev, buf, 0x##offset - 1); \
return show_temp(dev, buf, offset - 1); \
} \
static ssize_t show_temp_##offset##_min (struct device *dev, char *buf) \
{ \
return show_temp_min(dev, buf, 0x##offset - 1); \
return show_temp_min(dev, buf, offset - 1); \
} \
static ssize_t show_temp_##offset##_max (struct device *dev, char *buf) \
{ \
return show_temp_max(dev, buf, 0x##offset - 1); \
return show_temp_max(dev, buf, offset - 1); \
} \
static ssize_t show_temp_##offset##_crit (struct device *dev, char *buf) \
{ \
return show_temp_crit(dev, buf, 0x##offset - 1); \
return show_temp_crit(dev, buf, offset - 1); \
} \
static ssize_t set_temp_##offset##_min (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_temp_min(dev, buf, count, 0x##offset - 1); \
return set_temp_min(dev, buf, count, offset - 1); \
} \
static ssize_t set_temp_##offset##_max (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_temp_max(dev, buf, count, 0x##offset - 1); \
return set_temp_max(dev, buf, count, offset - 1); \
} \
static ssize_t set_temp_##offset##_crit (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_temp_crit(dev, buf, count, 0x##offset - 1); \
return set_temp_crit(dev, buf, count, offset - 1); \
} \
static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, \
NULL); \
......@@ -799,7 +799,7 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
device_create_file(&new_client->dev, &dev_attr_fan1_input);
device_create_file(&new_client->dev, &dev_attr_fan1_div);
device_create_file(&new_client->dev, &dev_attr_fan1_min);
device_create_file(&new_client->dev, &dev_attr_fan1_pwm);
device_create_file(&new_client->dev, &dev_attr_pwm1);
device_create_file(&new_client->dev, &dev_attr_auto_fan1_channel);
device_create_file(&new_client->dev, &dev_attr_temp1_input);
device_create_file(&new_client->dev, &dev_attr_temp1_min);
......@@ -826,7 +826,7 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
device_create_file(&new_client->dev, &dev_attr_fan2_input);
device_create_file(&new_client->dev, &dev_attr_fan2_div);
device_create_file(&new_client->dev, &dev_attr_fan2_min);
device_create_file(&new_client->dev, &dev_attr_fan2_pwm);
device_create_file(&new_client->dev, &dev_attr_pwm2);
device_create_file(&new_client->dev,
&dev_attr_auto_fan2_channel);
device_create_file(&new_client->dev, &dev_attr_temp3_input);
......
......@@ -266,29 +266,29 @@ set_in_reg(MAX, max)
static ssize_t \
show_in##offset (struct device *dev, char *buf) \
{ \
return show_in(dev, buf, 0x##offset); \
return show_in(dev, buf, offset); \
} \
static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
show_in##offset, NULL); \
static ssize_t \
show_in##offset##_min (struct device *dev, char *buf) \
{ \
return show_in_min(dev, buf, 0x##offset); \
return show_in_min(dev, buf, offset); \
} \
static ssize_t \
show_in##offset##_max (struct device *dev, char *buf) \
{ \
return show_in_max(dev, buf, 0x##offset); \
return show_in_max(dev, buf, offset); \
} \
static ssize_t set_in##offset##_min (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_in_min(dev, buf, count, 0x##offset); \
return set_in_min(dev, buf, count, offset); \
} \
static ssize_t set_in##offset##_max (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_in_max(dev, buf, count, 0x##offset); \
return set_in_max(dev, buf, count, offset); \
} \
static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
show_in##offset##_min, set_in##offset##_min); \
......@@ -591,12 +591,12 @@ static ssize_t set_pwm_enable1(struct device *dev, const char *buf,
return count;
}
static DEVICE_ATTR(fan1_pwm, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1);
static DEVICE_ATTR(fan1_pwm_enable, S_IRUGO | S_IWUSR,
static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1);
static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
show_pwm_enable1, set_pwm_enable1);
#define device_create_file_pwm1(client) do { \
device_create_file(&new_client->dev, &dev_attr_fan1_pwm); \
device_create_file(&new_client->dev, &dev_attr_fan1_pwm_enable); \
device_create_file(&new_client->dev, &dev_attr_pwm1); \
device_create_file(&new_client->dev, &dev_attr_pwm1_enable); \
} while (0)
/* This function is called when:
......
......@@ -96,7 +96,7 @@ static struct i2c_driver ds1621_driver = {
.detach_client = ds1621_detach_client,
};
static int ds1621_id = 0;
static int ds1621_id;
/* All registers are word-sized, except for the configuration register.
DS1621 uses a high-byte first convention, which is exactly opposite to
......
......@@ -86,7 +86,7 @@ static struct i2c_driver eeprom_driver = {
.detach_client = eeprom_detach_client,
};
static int eeprom_id = 0;
static int eeprom_id;
static void eeprom_update_client(struct i2c_client *client, u8 slice)
{
......
......@@ -156,7 +156,7 @@ struct fscher_data {
* Internal variables
*/
static int fscher_id = 0;
static int fscher_id;
/*
* Sysfs stuff
......
......@@ -164,7 +164,7 @@ static struct i2c_driver gl518_driver = {
* Internal variables
*/
static int gl518_id = 0;
static int gl518_id;
/*
* Sysfs stuff
......@@ -217,7 +217,8 @@ static ssize_t set_##suffix(struct device *dev, const char *buf, \
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct gl518_data *data = i2c_get_clientdata(client); \
data->value = type##_TO_REG(simple_strtol(buf, NULL, 10)); \
long val = simple_strtol(buf, NULL, 10); \
data->value = type##_TO_REG(val); \
gl518_write_value(client, reg, data->value); \
return count; \
}
......@@ -229,7 +230,8 @@ static ssize_t set_##suffix(struct device *dev, const char *buf, \
struct i2c_client *client = to_i2c_client(dev); \
struct gl518_data *data = i2c_get_clientdata(client); \
int regvalue = gl518_read_value(client, reg); \
data->value = type##_TO_REG(simple_strtoul(buf, NULL, 10)); \
unsigned long val = simple_strtoul(buf, NULL, 10); \
data->value = type##_TO_REG(val); \
regvalue = (regvalue & ~mask) | (data->value << shift); \
gl518_write_value(client, reg, regvalue); \
return count; \
......
......@@ -105,6 +105,10 @@ static int update_vbat;
/* Reset the registers on init if true */
static int reset;
/* Chip Type */
static u16 chip_type;
/* Many IT87 constants specified below */
/* Length of ISA address segment */
......@@ -226,7 +230,7 @@ static struct i2c_driver it87_driver = {
.detach_client = it87_detach_client,
};
static int it87_id = 0;
static int it87_id;
static ssize_t show_in(struct device *dev, char *buf, int nr)
{
......@@ -273,7 +277,7 @@ static ssize_t set_in_max(struct device *dev, const char *buf,
static ssize_t \
show_in##offset (struct device *dev, char *buf) \
{ \
return show_in(dev, buf, 0x##offset); \
return show_in(dev, buf, offset); \
} \
static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);
......@@ -281,22 +285,22 @@ static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);
static ssize_t \
show_in##offset##_min (struct device *dev, char *buf) \
{ \
return show_in_min(dev, buf, 0x##offset); \
return show_in_min(dev, buf, offset); \
} \
static ssize_t \
show_in##offset##_max (struct device *dev, char *buf) \
{ \
return show_in_max(dev, buf, 0x##offset); \
return show_in_max(dev, buf, offset); \
} \
static ssize_t set_in##offset##_min (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_in_min(dev, buf, count, 0x##offset); \
return set_in_min(dev, buf, count, offset); \
} \
static ssize_t set_in##offset##_max (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_in_max(dev, buf, count, 0x##offset); \
return set_in_max(dev, buf, count, offset); \
} \
static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
show_in##offset##_min, set_in##offset##_min); \
......@@ -360,27 +364,27 @@ static ssize_t set_temp_min(struct device *dev, const char *buf,
#define show_temp_offset(offset) \
static ssize_t show_temp_##offset (struct device *dev, char *buf) \
{ \
return show_temp(dev, buf, 0x##offset - 1); \
return show_temp(dev, buf, offset - 1); \
} \
static ssize_t \
show_temp_##offset##_max (struct device *dev, char *buf) \
{ \
return show_temp_max(dev, buf, 0x##offset - 1); \
return show_temp_max(dev, buf, offset - 1); \
} \
static ssize_t \
show_temp_##offset##_min (struct device *dev, char *buf) \
{ \
return show_temp_min(dev, buf, 0x##offset - 1); \
return show_temp_min(dev, buf, offset - 1); \
} \
static ssize_t set_temp_##offset##_max (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_temp_max(dev, buf, count, 0x##offset - 1); \
return set_temp_max(dev, buf, count, offset - 1); \
} \
static ssize_t set_temp_##offset##_min (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_temp_min(dev, buf, count, 0x##offset - 1); \
return set_temp_min(dev, buf, count, offset - 1); \
} \
static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL); \
static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
......@@ -423,12 +427,12 @@ static ssize_t set_sensor(struct device *dev, const char *buf,
#define show_sensor_offset(offset) \
static ssize_t show_sensor_##offset (struct device *dev, char *buf) \
{ \
return show_sensor(dev, buf, 0x##offset - 1); \
return show_sensor(dev, buf, offset - 1); \
} \
static ssize_t set_sensor_##offset (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_sensor(dev, buf, count, 0x##offset - 1); \
return set_sensor(dev, buf, count, offset - 1); \
} \
static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
show_sensor_##offset, set_sensor_##offset);
......@@ -505,25 +509,25 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
#define show_fan_offset(offset) \
static ssize_t show_fan_##offset (struct device *dev, char *buf) \
{ \
return show_fan(dev, buf, 0x##offset - 1); \
return show_fan(dev, buf, offset - 1); \
} \
static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \
{ \
return show_fan_min(dev, buf, 0x##offset - 1); \
return show_fan_min(dev, buf, offset - 1); \
} \
static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \
{ \
return show_fan_div(dev, buf, 0x##offset - 1); \
return show_fan_div(dev, buf, offset - 1); \
} \
static ssize_t set_fan_##offset##_min (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_fan_min(dev, buf, count, 0x##offset - 1); \
return set_fan_min(dev, buf, count, offset - 1); \
} \
static ssize_t set_fan_##offset##_div (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_fan_div(dev, buf, count, 0x##offset - 1); \
return set_fan_div(dev, buf, count, offset - 1); \
} \
static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL); \
static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
......@@ -592,9 +596,9 @@ static int it87_find(int *address)
u16 val;
superio_enter();
val = (superio_inb(DEVID) << 8) |
chip_type = (superio_inb(DEVID) << 8) |
superio_inb(DEVID + 1);
if (val != IT8712F_DEVID) {
if (chip_type != IT8712F_DEVID) {
superio_exit();
return -ENODEV;
}
......@@ -691,11 +695,9 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind)
if (kind <= 0) {
i = it87_read_value(new_client, IT87_REG_CHIPID);
if (i == 0x90) {
u16 val;
kind = it87;
val = (superio_inb(DEVID) << 8) |
superio_inb(DEVID + 1);
if (val == IT8712F_DEVID) kind = it8712;
if ((is_isa) && (chip_type == IT8712F_DEVID))
kind = it8712;
}
else {
if (kind == 0)
......
......@@ -74,7 +74,7 @@ static struct i2c_driver lm75_driver = {
.detach_client = lm75_detach_client,
};
static int lm75_id = 0;
static int lm75_id;
#define show(value) \
static ssize_t show_##value(struct device *dev, char *buf) \
......
......@@ -83,7 +83,7 @@ static struct i2c_driver lm77_driver = {
.detach_client = lm77_detach_client,
};
static int lm77_id = 0;
static int lm77_id;
/* straight from the datasheet */
#define LM77_TEMP_MIN (-55000)
......
......@@ -229,29 +229,29 @@ static ssize_t set_in_max(struct device *dev, const char *buf,
static ssize_t \
show_in##offset (struct device *dev, char *buf) \
{ \
return show_in(dev, buf, 0x##offset); \
return show_in(dev, buf, offset); \
} \
static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
show_in##offset, NULL); \
static ssize_t \
show_in##offset##_min (struct device *dev, char *buf) \
{ \
return show_in_min(dev, buf, 0x##offset); \
return show_in_min(dev, buf, offset); \
} \
static ssize_t \
show_in##offset##_max (struct device *dev, char *buf) \
{ \
return show_in_max(dev, buf, 0x##offset); \
return show_in_max(dev, buf, offset); \
} \
static ssize_t set_in##offset##_min (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_in_min(dev, buf, count, 0x##offset); \
return set_in_min(dev, buf, count, offset); \
} \
static ssize_t set_in##offset##_max (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_in_max(dev, buf, count, 0x##offset); \
return set_in_max(dev, buf, count, offset); \
} \
static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
show_in##offset##_min, set_in##offset##_min); \
......@@ -375,20 +375,20 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
#define show_fan_offset(offset) \
static ssize_t show_fan_##offset (struct device *dev, char *buf) \
{ \
return show_fan(dev, buf, 0x##offset - 1); \
return show_fan(dev, buf, offset - 1); \
} \
static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \
{ \
return show_fan_min(dev, buf, 0x##offset - 1); \
return show_fan_min(dev, buf, offset - 1); \
} \
static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \
{ \
return show_fan_div(dev, buf, 0x##offset - 1); \
return show_fan_div(dev, buf, offset - 1); \
} \
static ssize_t set_fan_##offset##_min (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_fan_min(dev, buf, count, 0x##offset - 1); \
return set_fan_min(dev, buf, count, offset - 1); \
} \
static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
......@@ -692,26 +692,12 @@ static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value)
/* Called when we have found a new LM78. It should set limits, etc. */
static void lm78_init_client(struct i2c_client *client)
{
struct lm78_data *data = i2c_get_clientdata(client);
int vid;
/* Reset all except Watchdog values and last conversion values
This sets fan-divs to 2, among others */
lm78_write_value(client, LM78_REG_CONFIG, 0x80);
vid = lm78_read_value(client, LM78_REG_VID_FANDIV) & 0x0f;
if (data->type == lm79)
vid |=
(lm78_read_value(client, LM78_REG_CHIPID) & 0x01) << 4;
else
vid |= 0x10;
vid = VID_FROM_REG(vid);
u8 config = lm78_read_value(client, LM78_REG_CONFIG);
/* Start monitoring */
lm78_write_value(client, LM78_REG_CONFIG,
(lm78_read_value(client, LM78_REG_CONFIG) & 0xf7)
| 0x01);
if (!(config & 0x01))
lm78_write_value(client, LM78_REG_CONFIG,
(config & 0xf7) | 0x01);
}
static struct lm78_data *lm78_update_device(struct device *dev)
......
......@@ -145,7 +145,7 @@ static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value);
* Internal variables
*/
static int lm80_id = 0;
static int lm80_id;
/*
* Driver data (common to all clients)
......@@ -262,14 +262,15 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
{
struct i2c_client *client = to_i2c_client(dev);
struct lm80_data *data = i2c_get_clientdata(client);
unsigned long min;
unsigned long min, val;
u8 reg;
/* Save fan_min */
min = FAN_FROM_REG(data->fan_min[nr],
DIV_FROM_REG(data->fan_div[nr]));
data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10));
val = simple_strtoul(buf, NULL, 10);
data->fan_div[nr] = DIV_TO_REG(val);
reg = (lm80_read_value(client, LM80_REG_FANDIV) & ~(3 << (2 * (nr + 1))))
| (data->fan_div[nr] << (2 * (nr + 1)));
......
......@@ -80,13 +80,14 @@ SENSORS_INSMOD_1(lm83);
/*
* Conversions and various macros
* The LM83 uses signed 8-bit values.
* The LM83 uses signed 8-bit values with LSB = 1 degree Celcius.
*/
#define TEMP_FROM_REG(val) (((val) > 127 ? (val) - 0x100 : (val)) * 1000)
#define TEMP_TO_REG(val) ((val) <= -50000 ? -50 + 0x100 : (val) >= 127000 ? 127 : \
(val) > -500 ? ((val)+500) / 1000 : \
((val)-500) / 1000 + 0x100)
#define TEMP_FROM_REG(val) ((val) * 1000)
#define TEMP_TO_REG(val) ((val) <= -128000 ? -128 : \
(val) >= 127000 ? 127 : \
(val) < 0 ? ((val) - 500) / 1000 : \
((val) + 500) / 1000)
static const u8 LM83_REG_R_TEMP[] = {
LM83_REG_R_LOCAL_TEMP,
......@@ -142,9 +143,9 @@ struct lm83_data {
unsigned long last_updated; /* in jiffies */
/* registers values */
u8 temp_input[4];
u8 temp_high[4];
u8 temp_crit;
s8 temp_input[4];
s8 temp_high[4];
s8 temp_crit;
u16 alarms; /* bitvector, combined */
};
......@@ -152,7 +153,7 @@ struct lm83_data {
* Internal variables
*/
static int lm83_id = 0;
static int lm83_id;
/*
* Sysfs stuff
......@@ -180,7 +181,8 @@ static ssize_t set_temp_##suffix(struct device *dev, const char *buf, \
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct lm83_data *data = i2c_get_clientdata(client); \
data->value = TEMP_TO_REG(simple_strtol(buf, NULL, 10)); \
long val = simple_strtol(buf, NULL, 10); \
data->value = TEMP_TO_REG(val); \
i2c_smbus_write_byte_data(client, reg, data->value); \
return count; \
}
......
......@@ -405,7 +405,7 @@ static struct i2c_driver lm85_driver = {
};
/* Unique ID assigned to each LM85 detected */
static int lm85_id = 0;
static int lm85_id;
/* 4 Fans */
......@@ -437,16 +437,16 @@ static ssize_t set_fan_min(struct device *dev, const char *buf,
#define show_fan_offset(offset) \
static ssize_t show_fan_##offset (struct device *dev, char *buf) \
{ \
return show_fan(dev, buf, 0x##offset - 1); \
return show_fan(dev, buf, offset - 1); \
} \
static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \
{ \
return show_fan_min(dev, buf, 0x##offset - 1); \
return show_fan_min(dev, buf, offset - 1); \
} \
static ssize_t set_fan_##offset##_min (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_fan_min(dev, buf, count, 0x##offset - 1); \
return set_fan_min(dev, buf, count, offset - 1); \
} \
static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
......@@ -527,20 +527,21 @@ static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr)
#define show_pwm_reg(offset) \
static ssize_t show_pwm_##offset (struct device *dev, char *buf) \
{ \
return show_pwm(dev, buf, 0x##offset - 1); \
return show_pwm(dev, buf, offset - 1); \
} \
static ssize_t set_pwm_##offset (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_pwm(dev, buf, count, 0x##offset - 1); \
return set_pwm(dev, buf, count, offset - 1); \
} \
static ssize_t show_pwm_enable##offset (struct device *dev, char *buf) \
{ \
return show_pwm_enable(dev, buf, 0x##offset - 1); \
return show_pwm_enable(dev, buf, offset - 1); \
} \
static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, \
static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
show_pwm_##offset, set_pwm_##offset); \
static DEVICE_ATTR(fan##offset##_pwm_enable, S_IRUGO, show_pwm_enable##offset, NULL);
static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO, \
show_pwm_enable##offset, NULL);
show_pwm_reg(1);
show_pwm_reg(2);
......@@ -594,25 +595,25 @@ static ssize_t set_in_max(struct device *dev, const char *buf,
#define show_in_reg(offset) \
static ssize_t show_in_##offset (struct device *dev, char *buf) \
{ \
return show_in(dev, buf, 0x##offset); \
return show_in(dev, buf, offset); \
} \
static ssize_t show_in_##offset##_min (struct device *dev, char *buf) \
{ \
return show_in_min(dev, buf, 0x##offset); \
return show_in_min(dev, buf, offset); \
} \
static ssize_t show_in_##offset##_max (struct device *dev, char *buf) \
{ \
return show_in_max(dev, buf, 0x##offset); \
return show_in_max(dev, buf, offset); \
} \
static ssize_t set_in_##offset##_min (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_in_min(dev, buf, count, 0x##offset); \
return set_in_min(dev, buf, count, offset); \
} \
static ssize_t set_in_##offset##_max (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_in_max(dev, buf, count, 0x##offset); \
return set_in_max(dev, buf, count, offset); \
} \
static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in_##offset, NULL); \
static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
......@@ -674,25 +675,25 @@ static ssize_t set_temp_max(struct device *dev, const char *buf,
#define show_temp_reg(offset) \
static ssize_t show_temp_##offset (struct device *dev, char *buf) \
{ \
return show_temp(dev, buf, 0x##offset - 1); \
return show_temp(dev, buf, offset - 1); \
} \
static ssize_t show_temp_##offset##_min (struct device *dev, char *buf) \
{ \
return show_temp_min(dev, buf, 0x##offset - 1); \
return show_temp_min(dev, buf, offset - 1); \
} \
static ssize_t show_temp_##offset##_max (struct device *dev, char *buf) \
{ \
return show_temp_max(dev, buf, 0x##offset - 1); \
return show_temp_max(dev, buf, offset - 1); \
} \
static ssize_t set_temp_##offset##_min (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_temp_min(dev, buf, count, 0x##offset - 1); \
return set_temp_min(dev, buf, count, offset - 1); \
} \
static ssize_t set_temp_##offset##_max (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_temp_max(dev, buf, count, 0x##offset - 1); \
return set_temp_max(dev, buf, count, offset - 1); \
} \
static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL); \
static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
......@@ -707,6 +708,8 @@ show_temp_reg(3);
int lm85_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
return i2c_detect(adapter, &addr_data, lm85_detect);
}
......@@ -843,12 +846,12 @@ int lm85_detect(struct i2c_adapter *adapter, int address,
device_create_file(&new_client->dev, &dev_attr_fan2_min);
device_create_file(&new_client->dev, &dev_attr_fan3_min);
device_create_file(&new_client->dev, &dev_attr_fan4_min);
device_create_file(&new_client->dev, &dev_attr_fan1_pwm);
device_create_file(&new_client->dev, &dev_attr_fan2_pwm);
device_create_file(&new_client->dev, &dev_attr_fan3_pwm);
device_create_file(&new_client->dev, &dev_attr_fan1_pwm_enable);
device_create_file(&new_client->dev, &dev_attr_fan2_pwm_enable);
device_create_file(&new_client->dev, &dev_attr_fan3_pwm_enable);
device_create_file(&new_client->dev, &dev_attr_pwm1);
device_create_file(&new_client->dev, &dev_attr_pwm2);
device_create_file(&new_client->dev, &dev_attr_pwm3);
device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
device_create_file(&new_client->dev, &dev_attr_pwm3_enable);
device_create_file(&new_client->dev, &dev_attr_in0_input);
device_create_file(&new_client->dev, &dev_attr_in1_input);
device_create_file(&new_client->dev, &dev_attr_in2_input);
......
/*
* lm87.c
*
* Copyright (C) 2000 Frodo Looijaard <frodol@dds.nl>
* Philip Edelbrock <phil@netroedge.com>
* Stephen Rousset <stephen.rousset@rocketlogix.com>
* Dan Eaton <dan.eaton@rocketlogix.com>
* Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
*
* Original port to Linux 2.6 by Jeff Oliver.
*
* The LM87 is a sensor chip made by National Semiconductor. It monitors up
* to 8 voltages (including its own power source), up to three temperatures
* (its own plus up to two external ones) and up to two fans. The default
* configuration is 6 voltages, two temperatures and two fans (see below).
* Voltages are scaled internally with ratios such that the nominal value of
* each voltage correspond to a register value of 192 (which means a
* resolution of about 0.5% of the nominal value). Temperature values are
* reported 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/LM87.html
*
* Some functions share pins, so not all functions are available at the same
* time. Which are depends on the hardware setup. This driver assumes that
* the BIOS configured the chip correctly. In that respect, it differs from
* the original driver (from lm_sensors for Linux 2.4), which would force the
* LM87 to an arbitrary, compile-time chosen mode, regardless of the actual
* chipset wiring.
* For reference, here is the list of exclusive functions:
* - in0+in5 (default) or temp3
* - fan1 (default) or in6
* - fan2 (default) or in7
* - VID lines (default) or IRQ lines (not handled by this driver)
*
* The LM87 additionally features an analog output, supposedly usable to
* control the speed of a fan. All new chips use pulse width modulation
* instead. The LM87 is the only hardware monitoring chipset I know of
* which uses amplitude modulation. Be careful when using this feature.
*
* 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/config.h>
#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>
/*
* Addresses to scan
* LM87 has three possible addresses: 0x2c, 0x2d and 0x2e.
*/
static unsigned short normal_i2c[] = { I2C_CLIENT_END };
static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, 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(lm87);
/*
* The LM87 registers
*/
/* nr in 0..5 */
#define LM87_REG_IN(nr) (0x20 + (nr))
#define LM87_REG_IN_MAX(nr) (0x2B + (nr) * 2)
#define LM87_REG_IN_MIN(nr) (0x2C + (nr) * 2)
/* nr in 0..1 */
#define LM87_REG_AIN(nr) (0x28 + (nr))
#define LM87_REG_AIN_MIN(nr) (0x1A + (nr))
#define LM87_REG_AIN_MAX(nr) (0x3B + (nr))
static u8 LM87_REG_TEMP[3] = { 0x27, 0x26, 0x20 };
static u8 LM87_REG_TEMP_HIGH[3] = { 0x39, 0x37, 0x2B };
static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C };
#define LM87_REG_TEMP_HW_INT_LOCK 0x13
#define LM87_REG_TEMP_HW_EXT_LOCK 0x14
#define LM87_REG_TEMP_HW_INT 0x17
#define LM87_REG_TEMP_HW_EXT 0x18
/* nr in 0..1 */
#define LM87_REG_FAN(nr) (0x28 + (nr))
#define LM87_REG_FAN_MIN(nr) (0x3B + (nr))
#define LM87_REG_AOUT 0x19
#define LM87_REG_CONFIG 0x40
#define LM87_REG_CHANNEL_MODE 0x16
#define LM87_REG_VID_FAN_DIV 0x47
#define LM87_REG_VID4 0x49
#define LM87_REG_ALARMS1 0x41
#define LM87_REG_ALARMS2 0x42
#define LM87_REG_COMPANY_ID 0x3E
#define LM87_REG_REVISION 0x3F
/*
* Conversions and various macros
* The LM87 uses signed 8-bit values for temperatures.
*/
#define IN_FROM_REG(reg,scale) (((reg) * (scale) + 96) / 192)
#define IN_TO_REG(val,scale) ((val) <= 0 ? 0 : \
(val) * 192 >= (scale) * 255 ? 255 : \
((val) * 192 + (scale)/2) / (scale))
#define TEMP_FROM_REG(reg) ((reg) * 1000)
#define TEMP_TO_REG(val) ((val) <= -127500 ? -128 : \
(val) >= 126500 ? 127 : \
(((val) < 0 ? (val)-500 : (val)+500) / 1000))
#define FAN_FROM_REG(reg,div) ((reg) == 255 || (reg) == 0 ? 0 : \
1350000 + (reg)*(div) / 2) / ((reg)*(div))
#define FAN_TO_REG(val,div) ((val)*(div) * 255 <= 1350000 ? 255 : \
(1350000 + (val)*(div) / 2) / ((val)*(div)))
#define FAN_DIV_FROM_REG(reg) (1 << (reg))
/* analog out is 9.80mV/LSB */
#define AOUT_FROM_REG(reg) (((reg) * 98 + 5) / 10)
#define AOUT_TO_REG(val) ((val) <= 0 ? 0 : \
(val) >= 2500 ? 255 : \
((val) * 10 + 49) / 98)
/* nr in 0..1 */
#define CHAN_NO_FAN(nr) (1 << (nr))
#define CHAN_TEMP3 (1 << 2)
#define CHAN_VCC_5V (1 << 3)
#define CHAN_NO_VID (1 << 8)
/*
* Functions declaration
*/
static int lm87_attach_adapter(struct i2c_adapter *adapter);
static int lm87_detect(struct i2c_adapter *adapter, int address, int kind);
static void lm87_init_client(struct i2c_client *client);
static int lm87_detach_client(struct i2c_client *client);
static struct lm87_data *lm87_update_device(struct device *dev);
/*
* Driver data (common to all clients)
*/
static struct i2c_driver lm87_driver = {
.owner = THIS_MODULE,
.name = "lm87",
.id = I2C_DRIVERID_LM87,
.flags = I2C_DF_NOTIFY,
.attach_adapter = lm87_attach_adapter,
.detach_client = lm87_detach_client,
};
/*
* Client data (each client gets its own)
*/
struct lm87_data {
struct i2c_client client;
struct semaphore update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* In jiffies */
u8 channel; /* register value */
u8 in[8]; /* register value */
u8 in_max[8]; /* register value */
u8 in_min[8]; /* register value */
u16 in_scale[8];
s8 temp[3]; /* register value */
s8 temp_high[3]; /* register value */
s8 temp_low[3]; /* register value */
s8 temp_crit_int; /* min of two register values */
s8 temp_crit_ext; /* min of two register values */
u8 fan[2]; /* register value */
u8 fan_min[2]; /* register value */
u8 fan_div[2]; /* register value, shifted right */
u8 aout; /* register value */
u16 alarms; /* register values, combined */
u8 vid; /* register values, combined */
u8 vrm;
};
/*
* Internal variables
*/
static int lm87_id;
/*
* Sysfs stuff
*/
static inline int lm87_read_value(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_byte_data(client, reg);
}
static inline int lm87_write_value(struct i2c_client *client, u8 reg, u8 value)
{
return i2c_smbus_write_byte_data(client, reg, value);
}
#define show_in(offset) \
static ssize_t show_in##offset##_input(struct device *dev, char *buf) \
{ \
struct lm87_data *data = lm87_update_device(dev); \
return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \
data->in_scale[offset])); \
} \
static ssize_t show_in##offset##_min(struct device *dev, char *buf) \
{ \
struct lm87_data *data = lm87_update_device(dev); \
return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \
data->in_scale[offset])); \
} \
static ssize_t show_in##offset##_max(struct device *dev, char *buf) \
{ \
struct lm87_data *data = lm87_update_device(dev); \
return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \
data->in_scale[offset])); \
} \
static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
show_in##offset##_input, NULL);
show_in(0);
show_in(1);
show_in(2);
show_in(3);
show_in(4);
show_in(5);
show_in(6);
show_in(7);
static void set_in_min(struct device *dev, const char *buf, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm87_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
data->in_min[nr] = IN_TO_REG(val, data->in_scale[nr]);
lm87_write_value(client, nr<6 ? LM87_REG_IN_MIN(nr) :
LM87_REG_AIN_MIN(nr-6), data->in_min[nr]);
}
static void set_in_max(struct device *dev, const char *buf, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm87_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
data->in_max[nr] = IN_TO_REG(val, data->in_scale[nr]);
lm87_write_value(client, nr<6 ? LM87_REG_IN_MAX(nr) :
LM87_REG_AIN_MAX(nr-6), data->in_max[nr]);
}
#define set_in(offset) \
static ssize_t set_in##offset##_min(struct device *dev, \
const char *buf, size_t count) \
{ \
set_in_min(dev, buf, offset); \
return count; \
} \
static ssize_t set_in##offset##_max(struct device *dev, \
const char *buf, size_t count) \
{ \
set_in_max(dev, buf, offset); \
return count; \
} \
static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
show_in##offset##_min, set_in##offset##_min); \
static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
show_in##offset##_max, set_in##offset##_max);
set_in(0);
set_in(1);
set_in(2);
set_in(3);
set_in(4);
set_in(5);
set_in(6);
set_in(7);
#define show_temp(offset) \
static ssize_t show_temp##offset##_input(struct device *dev, char *buf) \
{ \
struct lm87_data *data = lm87_update_device(dev); \
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \
} \
static ssize_t show_temp##offset##_low(struct device *dev, char *buf) \
{ \
struct lm87_data *data = lm87_update_device(dev); \
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[offset-1])); \
} \
static ssize_t show_temp##offset##_high(struct device *dev, char *buf) \
{ \
struct lm87_data *data = lm87_update_device(dev); \
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[offset-1])); \
}\
static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
show_temp##offset##_input, NULL);
show_temp(1);
show_temp(2);
show_temp(3);
static void set_temp_low(struct device *dev, const char *buf, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm87_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
data->temp_low[nr] = TEMP_TO_REG(val);
lm87_write_value(client, LM87_REG_TEMP_LOW[nr], data->temp_low[nr]);
}
static void set_temp_high(struct device *dev, const char *buf, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm87_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
data->temp_high[nr] = TEMP_TO_REG(val);
lm87_write_value(client, LM87_REG_TEMP_HIGH[nr], data->temp_high[nr]);
}
#define set_temp(offset) \
static ssize_t set_temp##offset##_low(struct device *dev, \
const char *buf, size_t count) \
{ \
set_temp_low(dev, buf, offset-1); \
return count; \
} \
static ssize_t set_temp##offset##_high(struct device *dev, \
const char *buf, size_t count) \
{ \
set_temp_high(dev, buf, offset-1); \
return count; \
} \
static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
show_temp##offset##_high, set_temp##offset##_high); \
static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
show_temp##offset##_low, set_temp##offset##_low);
set_temp(1);
set_temp(2);
set_temp(3);
static ssize_t show_temp_crit_int(struct device *dev, char *buf)
{
struct lm87_data *data = lm87_update_device(dev);
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_int));
}
static ssize_t show_temp_crit_ext(struct device *dev, char *buf)
{
struct lm87_data *data = lm87_update_device(dev);
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_ext));
}
static DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit_int, NULL);
static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit_ext, NULL);
static DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit_ext, NULL);
#define show_fan(offset) \
static ssize_t show_fan##offset##_input(struct device *dev, char *buf) \
{ \
struct lm87_data *data = lm87_update_device(dev); \
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[offset-1], \
FAN_DIV_FROM_REG(data->fan_div[offset-1]))); \
} \
static ssize_t show_fan##offset##_min(struct device *dev, char *buf) \
{ \
struct lm87_data *data = lm87_update_device(dev); \
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[offset-1], \
FAN_DIV_FROM_REG(data->fan_div[offset-1]))); \
} \
static ssize_t show_fan##offset##_div(struct device *dev, char *buf) \
{ \
struct lm87_data *data = lm87_update_device(dev); \
return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[offset-1])); \
} \
static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
show_fan##offset##_input, NULL);
show_fan(1);
show_fan(2);
static void set_fan_min(struct device *dev, const char *buf, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm87_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
data->fan_min[nr] = FAN_TO_REG(val,
FAN_DIV_FROM_REG(data->fan_div[nr]));
lm87_write_value(client, LM87_REG_FAN_MIN(nr), data->fan_min[nr]);
}
/* Note: we save and restore the fan minimum here, because its value is
determined in part by the fan clock divider. This follows the principle
of least suprise; the user doesn't expect the fan minimum to change just
because the divider changed. */
static ssize_t set_fan_div(struct device *dev, const char *buf,
size_t count, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm87_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
unsigned long min = FAN_FROM_REG(data->fan_min[nr],
FAN_DIV_FROM_REG(data->fan_div[nr]));
u8 reg;
switch (val) {
case 1: data->fan_div[nr] = 0; break;
case 2: data->fan_div[nr] = 1; break;
case 4: data->fan_div[nr] = 2; break;
case 8: data->fan_div[nr] = 3; break;
default: return -EINVAL;
}
reg = lm87_read_value(client, LM87_REG_VID_FAN_DIV);
switch (nr) {
case 0:
reg = (reg & 0xCF) | (data->fan_div[0] << 4);
break;
case 1:
reg = (reg & 0x3F) | (data->fan_div[1] << 6);
break;
}
lm87_write_value(client, LM87_REG_VID_FAN_DIV, reg);
data->fan_min[nr] = FAN_TO_REG(min, val);
lm87_write_value(client, LM87_REG_FAN_MIN(nr),
data->fan_min[nr]);
return count;
}
#define set_fan(offset) \
static ssize_t set_fan##offset##_min(struct device *dev, const char *buf, \
size_t count) \
{ \
set_fan_min(dev, buf, offset-1); \
return count; \
} \
static ssize_t set_fan##offset##_div(struct device *dev, const char *buf, \
size_t count) \
{ \
return set_fan_div(dev, buf, count, offset-1); \
} \
static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
show_fan##offset##_min, set_fan##offset##_min); \
static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
show_fan##offset##_div, set_fan##offset##_div);
set_fan(1);
set_fan(2);
static ssize_t show_alarms(struct device *dev, char *buf)
{
struct lm87_data *data = lm87_update_device(dev);
return sprintf(buf, "%d\n", data->alarms);
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
static ssize_t show_vid(struct device *dev, char *buf)
{
struct lm87_data *data = lm87_update_device(dev);
return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
}
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
static ssize_t show_vrm(struct device *dev, char *buf)
{
struct lm87_data *data = lm87_update_device(dev);
return sprintf(buf, "%d\n", data->vrm);
}
static ssize_t set_vrm(struct device *dev, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm87_data *data = i2c_get_clientdata(client);
data->vrm = simple_strtoul(buf, NULL, 10);
return count;
}
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
static ssize_t show_aout(struct device *dev, char *buf)
{
struct lm87_data *data = lm87_update_device(dev);
return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout));
}
static ssize_t set_aout(struct device *dev, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm87_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
data->aout = AOUT_TO_REG(val);
lm87_write_value(client, LM87_REG_AOUT, data->aout);
return count;
}
static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
/*
* Real code
*/
static int lm87_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
return i2c_detect(adapter, &addr_data, lm87_detect);
}
/*
* The following function does more than just detection. If detection
* succeeds, it also registers the new chip.
*/
static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *new_client;
struct lm87_data *data;
int err = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
goto exit;
if (!(data = kmalloc(sizeof(struct lm87_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
memset(data, 0, sizeof(struct lm87_data));
/* The common I2C client data is placed right before the
LM87-specific data. */
new_client = &data->client;
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
new_client->driver = &lm87_driver;
new_client->flags = 0;
/* Default to an LM87 if forced */
if (kind == 0)
kind = lm87;
/* Now, we do the remaining detection. */
if (kind < 0) {
u8 rev = lm87_read_value(new_client, LM87_REG_REVISION);
if (rev < 0x01 || rev > 0x08
|| (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80)
|| lm87_read_value(new_client, LM87_REG_COMPANY_ID) != 0x02) {
dev_dbg(&adapter->dev,
"LM87 detection failed at 0x%02x.\n",
address);
goto exit_free;
}
}
/* We can fill in the remaining client fields */
strlcpy(new_client->name, "lm87", I2C_NAME_SIZE);
new_client->id = lm87_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 LM87 chip */
lm87_init_client(new_client);
data->in_scale[0] = 2500;
data->in_scale[1] = 2700;
data->in_scale[2] = (data->channel & CHAN_VCC_5V) ? 5000 : 3300;
data->in_scale[3] = 5000;
data->in_scale[4] = 12000;
data->in_scale[5] = 2700;
data->in_scale[6] = 1875;
data->in_scale[7] = 1875;
/* Register sysfs hooks */
device_create_file(&new_client->dev, &dev_attr_in1_input);
device_create_file(&new_client->dev, &dev_attr_in1_min);
device_create_file(&new_client->dev, &dev_attr_in1_max);
device_create_file(&new_client->dev, &dev_attr_in2_input);
device_create_file(&new_client->dev, &dev_attr_in2_min);
device_create_file(&new_client->dev, &dev_attr_in2_max);
device_create_file(&new_client->dev, &dev_attr_in3_input);
device_create_file(&new_client->dev, &dev_attr_in3_min);
device_create_file(&new_client->dev, &dev_attr_in3_max);
device_create_file(&new_client->dev, &dev_attr_in4_input);
device_create_file(&new_client->dev, &dev_attr_in4_min);
device_create_file(&new_client->dev, &dev_attr_in4_max);
if (data->channel & CHAN_NO_FAN(0)) {
device_create_file(&new_client->dev, &dev_attr_in6_input);
device_create_file(&new_client->dev, &dev_attr_in6_min);
device_create_file(&new_client->dev, &dev_attr_in6_max);
} else {
device_create_file(&new_client->dev, &dev_attr_fan1_input);
device_create_file(&new_client->dev, &dev_attr_fan1_min);
device_create_file(&new_client->dev, &dev_attr_fan1_div);
}
if (data->channel & CHAN_NO_FAN(1)) {
device_create_file(&new_client->dev, &dev_attr_in7_input);
device_create_file(&new_client->dev, &dev_attr_in7_min);
device_create_file(&new_client->dev, &dev_attr_in7_max);
} else {
device_create_file(&new_client->dev, &dev_attr_fan2_input);
device_create_file(&new_client->dev, &dev_attr_fan2_min);
device_create_file(&new_client->dev, &dev_attr_fan2_div);
}
device_create_file(&new_client->dev, &dev_attr_temp1_input);
device_create_file(&new_client->dev, &dev_attr_temp1_max);
device_create_file(&new_client->dev, &dev_attr_temp1_min);
device_create_file(&new_client->dev, &dev_attr_temp1_crit);
device_create_file(&new_client->dev, &dev_attr_temp2_input);
device_create_file(&new_client->dev, &dev_attr_temp2_max);
device_create_file(&new_client->dev, &dev_attr_temp2_min);
device_create_file(&new_client->dev, &dev_attr_temp2_crit);
if (data->channel & CHAN_TEMP3) {
device_create_file(&new_client->dev, &dev_attr_temp3_input);
device_create_file(&new_client->dev, &dev_attr_temp3_max);
device_create_file(&new_client->dev, &dev_attr_temp3_min);
device_create_file(&new_client->dev, &dev_attr_temp3_crit);
} else {
device_create_file(&new_client->dev, &dev_attr_in0_input);
device_create_file(&new_client->dev, &dev_attr_in0_min);
device_create_file(&new_client->dev, &dev_attr_in0_max);
device_create_file(&new_client->dev, &dev_attr_in5_input);
device_create_file(&new_client->dev, &dev_attr_in5_min);
device_create_file(&new_client->dev, &dev_attr_in5_max);
}
if (!(data->channel & CHAN_NO_VID)) {
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
device_create_file(&new_client->dev, &dev_attr_vrm);
}
device_create_file(&new_client->dev, &dev_attr_alarms);
device_create_file(&new_client->dev, &dev_attr_aout_output);
return 0;
exit_free:
kfree(data);
exit:
return err;
}
static void lm87_init_client(struct i2c_client *client)
{
struct lm87_data *data = i2c_get_clientdata(client);
u8 config;
data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE);
data->vrm = i2c_which_vrm();
config = lm87_read_value(client, LM87_REG_CONFIG);
if (!(config & 0x01)) {
int i;
/* Limits are left uninitialized after power-up */
for (i = 1; i < 6; i++) {
lm87_write_value(client, LM87_REG_IN_MIN(i), 0x00);
lm87_write_value(client, LM87_REG_IN_MAX(i), 0xFF);
}
for (i = 0; i < 2; i++) {
lm87_write_value(client, LM87_REG_TEMP_HIGH[i], 0x7F);
lm87_write_value(client, LM87_REG_TEMP_LOW[i], 0x00);
lm87_write_value(client, LM87_REG_AIN_MIN(i), 0x00);
lm87_write_value(client, LM87_REG_AIN_MAX(i), 0xFF);
}
if (data->channel & CHAN_TEMP3) {
lm87_write_value(client, LM87_REG_TEMP_HIGH[2], 0x7F);
lm87_write_value(client, LM87_REG_TEMP_LOW[2], 0x00);
} else {
lm87_write_value(client, LM87_REG_IN_MIN(0), 0x00);
lm87_write_value(client, LM87_REG_IN_MAX(0), 0xFF);
}
}
if ((config & 0x81) != 0x01) {
/* Start monitoring */
lm87_write_value(client, LM87_REG_CONFIG,
(config & 0xF7) | 0x01);
}
}
static int lm87_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(i2c_get_clientdata(client));
return 0;
}
static struct lm87_data *lm87_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm87_data *data = i2c_get_clientdata(client);
down(&data->update_lock);
if (jiffies - data->last_updated > HZ
|| jiffies < data->last_updated
|| !data->valid) {
int i, j;
dev_dbg(&client->dev, "Updating data.\n");
i = (data->channel & CHAN_TEMP3) ? 1 : 0;
j = (data->channel & CHAN_TEMP3) ? 5 : 6;
for (; i < j; 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));
}
for (i = 0; i < 2; i++) {
if (data->channel & CHAN_NO_FAN(i)) {
data->in[6+i] = lm87_read_value(client,
LM87_REG_AIN(i));
data->in_max[6+i] = lm87_read_value(client,
LM87_REG_AIN_MAX(i));
data->in_min[6+i] = lm87_read_value(client,
LM87_REG_AIN_MIN(i));
} else {
data->fan[i] = lm87_read_value(client,
LM87_REG_FAN(i));
data->fan_min[i] = lm87_read_value(client,
LM87_REG_FAN_MIN(i));
}
}
j = (data->channel & CHAN_TEMP3) ? 3 : 2;
for (i = 0 ; i < j; i++) {
data->temp[i] = lm87_read_value(client,
LM87_REG_TEMP[i]);
data->temp_high[i] = lm87_read_value(client,
LM87_REG_TEMP_HIGH[i]);
data->temp_low[i] = lm87_read_value(client,
LM87_REG_TEMP_LOW[i]);
}
i = lm87_read_value(client, LM87_REG_TEMP_HW_INT_LOCK);
j = lm87_read_value(client, LM87_REG_TEMP_HW_INT);
data->temp_crit_int = min(i, j);
i = lm87_read_value(client, LM87_REG_TEMP_HW_EXT_LOCK);
j = lm87_read_value(client, LM87_REG_TEMP_HW_EXT);
data->temp_crit_ext = min(i, j);
i = lm87_read_value(client, LM87_REG_VID_FAN_DIV);
data->fan_div[0] = (i >> 4) & 0x03;
data->fan_div[1] = (i >> 6) & 0x03;
data->vid = (i & 0x0F)
| (lm87_read_value(client, LM87_REG_VID4) & 0x01)
<< 4;
data->alarms = lm87_read_value(client, LM87_REG_ALARMS1)
| (lm87_read_value(client, LM87_REG_ALARMS2)
<< 8);
data->aout = lm87_read_value(client, LM87_REG_AOUT);
data->last_updated = jiffies;
data->valid = 1;
}
up(&data->update_lock);
return data;
}
static int __init sensors_lm87_init(void)
{
return i2c_add_driver(&lm87_driver);
}
static void __exit sensors_lm87_exit(void)
{
i2c_del_driver(&lm87_driver);
}
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org> and others");
MODULE_DESCRIPTION("LM87 driver");
MODULE_LICENSE("GPL");
module_init(sensors_lm87_init);
module_exit(sensors_lm87_exit);
......@@ -127,19 +127,24 @@ SENSORS_INSMOD_5(lm90, adm1032, lm99, lm86, max6657);
/*
* Conversions and various macros
* The LM90 uses signed 8-bit values for the local temperatures,
* and signed 11-bit values for the remote temperatures (except
* T_CRIT). Note that TEMP2_TO_REG does not round values, but
* stick to the nearest lower value instead. Fixing it is just
* not worth it.
* For local temperatures and limits, critical limits and the hysteresis
* value, the LM90 uses signed 8-bit values with LSB = 1 degree Celcius.
* For remote temperatures and limits, it uses signed 11-bit values with
* LSB = 0.125 degree Celcius, left-justified in 16-bit registers.
*/
#define TEMP1_FROM_REG(val) ((val & 0x80 ? val-0x100 : val) * 1000)
#define TEMP1_TO_REG(val) ((val < 0 ? val+0x100*1000 : val) / 1000)
#define TEMP2_FROM_REG(val) (((val & 0x8000 ? val-0x10000 : val) >> 5) * 125)
#define TEMP2_TO_REG(val) ((((val / 125) << 5) + (val < 0 ? 0x10000 : 0)) & 0xFFE0)
#define HYST_FROM_REG(val) (val * 1000)
#define HYST_TO_REG(val) (val <= 0 ? 0 : val >= 31000 ? 31 : val / 1000)
#define TEMP1_FROM_REG(val) ((val) * 1000)
#define TEMP1_TO_REG(val) ((val) <= -128000 ? -128 : \
(val) >= 127000 ? 127 : \
(val) < 0 ? ((val) - 500) / 1000 : \
((val) + 500) / 1000)
#define TEMP2_FROM_REG(val) ((val) / 32 * 125)
#define TEMP2_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) >= 30500 ? 31 : \
((val) + 500) / 1000)
/*
* Functions declaration
......@@ -176,18 +181,18 @@ struct lm90_data {
unsigned long last_updated; /* in jiffies */
/* registers values */
u8 temp_input1, temp_low1, temp_high1; /* local */
u16 temp_input2, temp_low2, temp_high2; /* remote, combined */
u8 temp_crit1, temp_crit2;
s8 temp_input1, temp_low1, temp_high1; /* local */
s16 temp_input2, temp_low2, temp_high2; /* remote, combined */
s8 temp_crit1, temp_crit2;
u8 temp_hyst;
u16 alarms; /* bitvector, combined */
u8 alarms; /* bitvector */
};
/*
* Internal variables
*/
static int lm90_id = 0;
static int lm90_id;
/*
* Sysfs stuff
......@@ -214,7 +219,8 @@ static ssize_t set_##value(struct device *dev, const char *buf, \
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct lm90_data *data = i2c_get_clientdata(client); \
data->value = TEMP1_TO_REG(simple_strtol(buf, NULL, 10)); \
long val = simple_strtol(buf, NULL, 10); \
data->value = TEMP1_TO_REG(val); \
i2c_smbus_write_byte_data(client, reg, data->value); \
return count; \
}
......@@ -224,7 +230,8 @@ static ssize_t set_##value(struct device *dev, const char *buf, \
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct lm90_data *data = i2c_get_clientdata(client); \
data->value = TEMP2_TO_REG(simple_strtol(buf, NULL, 10)); \
long val = simple_strtol(buf, NULL, 10); \
data->value = TEMP2_TO_REG(val); \
i2c_smbus_write_byte_data(client, regh, data->value >> 8); \
i2c_smbus_write_byte_data(client, regl, data->value & 0xff); \
return count; \
......@@ -241,7 +248,7 @@ static ssize_t show_##value(struct device *dev, char *buf) \
{ \
struct lm90_data *data = lm90_update_device(dev); \
return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->basereg) \
- HYST_FROM_REG(data->temp_hyst)); \
- TEMP1_FROM_REG(data->temp_hyst)); \
}
show_temp_hyst(temp_hyst1, temp_crit1);
show_temp_hyst(temp_hyst2, temp_crit2);
......
......@@ -120,7 +120,7 @@ struct max1619_data {
* Internal variables
*/
static int max1619_id = 0;
static int max1619_id;
/*
* Sysfs stuff
......@@ -145,7 +145,8 @@ static ssize_t set_##value(struct device *dev, const char *buf, \
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct max1619_data *data = i2c_get_clientdata(client); \
data->value = TEMP_TO_REG(simple_strtol(buf, NULL, 10)); \
long val = simple_strtol(buf, NULL, 10); \
data->value = TEMP_TO_REG(val); \
i2c_smbus_write_byte_data(client, reg, data->value); \
return count; \
}
......
......@@ -77,7 +77,7 @@ static struct i2c_driver pcf8574_driver = {
.detach_client = pcf8574_detach_client,
};
static int pcf8574_id = 0;
static int pcf8574_id;
/* following are the sysfs callback functions */
static ssize_t show_read(struct device *dev, char *buf)
......
......@@ -99,7 +99,7 @@ static struct i2c_driver pcf8591_driver = {
.detach_client = pcf8591_detach_client,
};
static int pcf8591_id = 0;
static int pcf8591_id;
/* following are the sysfs callback functions */
#define show_in_channel(channel) \
......
......@@ -182,13 +182,13 @@ static ssize_t get_fan_div(struct device *dev, char *buf, int nr)
return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
}
static ssize_t get_fan_pwm(struct device *dev, char *buf, int nr)
static ssize_t get_pwm(struct device *dev, char *buf, int nr)
{
struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr]));
}
static ssize_t get_fan_pwm_en(struct device *dev, char *buf, int nr)
static ssize_t get_pwm_en(struct device *dev, char *buf, int nr)
{
struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[nr]));
......@@ -256,7 +256,7 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
return count;
}
static ssize_t set_fan_pwm(struct device *dev, const char *buf,
static ssize_t set_pwm(struct device *dev, const char *buf,
size_t count, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
......@@ -275,7 +275,7 @@ static ssize_t set_fan_pwm(struct device *dev, const char *buf,
return count;
}
static ssize_t set_fan_pwm_en(struct device *dev, const char *buf,
static ssize_t set_pwm_en(struct device *dev, const char *buf,
size_t count, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
......@@ -298,43 +298,43 @@ static ssize_t set_fan_pwm_en(struct device *dev, const char *buf,
#define fan_present(offset) \
static ssize_t get_fan##offset (struct device *dev, char *buf) \
{ \
return get_fan(dev, buf, 0x##offset - 1); \
return get_fan(dev, buf, offset - 1); \
} \
static ssize_t get_fan##offset##_min (struct device *dev, char *buf) \
{ \
return get_fan_min(dev, buf, 0x##offset - 1); \
return get_fan_min(dev, buf, offset - 1); \
} \
static ssize_t set_fan##offset##_min (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_fan_min(dev, buf, count, 0x##offset - 1); \
return set_fan_min(dev, buf, count, offset - 1); \
} \
static ssize_t get_fan##offset##_div (struct device *dev, char *buf) \
{ \
return get_fan_div(dev, buf, 0x##offset - 1); \
return get_fan_div(dev, buf, offset - 1); \
} \
static ssize_t set_fan##offset##_div (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_fan_div(dev, buf, count, 0x##offset - 1); \
return set_fan_div(dev, buf, count, offset - 1); \
} \
static ssize_t get_fan##offset##_pwm (struct device *dev, char *buf) \
static ssize_t get_pwm##offset (struct device *dev, char *buf) \
{ \
return get_fan_pwm(dev, buf, 0x##offset - 1); \
return get_pwm(dev, buf, offset - 1); \
} \
static ssize_t set_fan##offset##_pwm (struct device *dev, \
static ssize_t set_pwm##offset (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_fan_pwm(dev, buf, count, 0x##offset - 1); \
return set_pwm(dev, buf, count, offset - 1); \
} \
static ssize_t get_fan##offset##_pwm_en (struct device *dev, char *buf) \
static ssize_t get_pwm##offset##_en (struct device *dev, char *buf) \
{ \
return get_fan_pwm_en(dev, buf, 0x##offset - 1); \
return get_pwm_en(dev, buf, offset - 1); \
} \
static ssize_t set_fan##offset##_pwm_en (struct device *dev, \
static ssize_t set_pwm##offset##_en (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_fan_pwm_en(dev, buf, count, 0x##offset - 1); \
return set_pwm_en(dev, buf, count, offset - 1); \
} \
static DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan##offset, \
NULL); \
......@@ -342,10 +342,10 @@ static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
get_fan##offset##_min, set_fan##offset##_min); \
static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
get_fan##offset##_div, set_fan##offset##_div); \
static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, \
get_fan##offset##_pwm, set_fan##offset##_pwm); \
static DEVICE_ATTR(fan##offset##_pwm_enable, S_IRUGO | S_IWUSR, \
get_fan##offset##_pwm_en, set_fan##offset##_pwm_en);
static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
get_pwm##offset, set_pwm##offset); \
static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
get_pwm##offset##_en, set_pwm##offset##_en);
fan_present(1);
fan_present(2);
......@@ -462,15 +462,15 @@ static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind)
if ((smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(0)) & 0x05)
== 0x04) {
device_create_file(&new_client->dev, &dev_attr_fan1_pwm);
device_create_file(&new_client->dev, &dev_attr_fan1_pwm_enable);
device_create_file(&new_client->dev, &dev_attr_pwm1);
device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
} else
dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, "
"skipping\n");
if ((smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05)
== 0x04) {
device_create_file(&new_client->dev, &dev_attr_fan2_pwm);
device_create_file(&new_client->dev, &dev_attr_fan2_pwm_enable);
device_create_file(&new_client->dev, &dev_attr_pwm2);
device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
} else
dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, "
"skipping\n");
......
......@@ -383,27 +383,27 @@ static ssize_t set_in_max(struct device *dev, const char *buf,
static ssize_t \
show_in##offset (struct device *dev, char *buf) \
{ \
return show_in(dev, buf, 0x##offset); \
return show_in(dev, buf, offset); \
} \
static ssize_t \
show_in##offset##_min (struct device *dev, char *buf) \
{ \
return show_in_min(dev, buf, 0x##offset); \
return show_in_min(dev, buf, offset); \
} \
static ssize_t \
show_in##offset##_max (struct device *dev, char *buf) \
{ \
return show_in_max(dev, buf, 0x##offset); \
return show_in_max(dev, buf, offset); \
} \
static ssize_t set_in##offset##_min (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_in_min(dev, buf, count, 0x##offset); \
return set_in_min(dev, buf, count, offset); \
} \
static ssize_t set_in##offset##_max (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_in_max(dev, buf, count, 0x##offset); \
return set_in_max(dev, buf, count, offset); \
} \
static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);\
static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
......@@ -451,27 +451,27 @@ static ssize_t set_temp_hyst(struct device *dev, const char *buf,
#define show_temp_offset(offset) \
static ssize_t show_temp_##offset (struct device *dev, char *buf) \
{ \
return show_temp(dev, buf, 0x##offset - 1); \
return show_temp(dev, buf, offset - 1); \
} \
static ssize_t \
show_temp_##offset##_over (struct device *dev, char *buf) \
{ \
return show_temp_over(dev, buf, 0x##offset - 1); \
return show_temp_over(dev, buf, offset - 1); \
} \
static ssize_t \
show_temp_##offset##_hyst (struct device *dev, char *buf) \
{ \
return show_temp_hyst(dev, buf, 0x##offset - 1); \
return show_temp_hyst(dev, buf, offset - 1); \
} \
static ssize_t set_temp_##offset##_over (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_temp_over(dev, buf, count, 0x##offset - 1); \
return set_temp_over(dev, buf, count, offset - 1); \
} \
static ssize_t set_temp_##offset##_hyst (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_temp_hyst(dev, buf, count, 0x##offset - 1); \
return set_temp_hyst(dev, buf, count, offset - 1); \
} \
static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);\
static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
......@@ -522,25 +522,25 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
#define show_fan_offset(offset) \
static ssize_t show_fan_##offset (struct device *dev, char *buf) \
{ \
return show_fan(dev, buf, 0x##offset - 1); \
return show_fan(dev, buf, offset - 1); \
} \
static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \
{ \
return show_fan_min(dev, buf, 0x##offset - 1); \
return show_fan_min(dev, buf, offset - 1); \
} \
static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \
{ \
return show_fan_div(dev, buf, 0x##offset - 1); \
return show_fan_div(dev, buf, offset - 1); \
} \
static ssize_t set_fan_##offset##_min (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_fan_min(dev, buf, count, 0x##offset - 1); \
return set_fan_min(dev, buf, count, offset - 1); \
} \
static ssize_t set_fan_##offset##_div (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_fan_div(dev, buf, count, 0x##offset - 1); \
return set_fan_div(dev, buf, count, offset - 1); \
} \
static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
......@@ -838,7 +838,7 @@ static struct pci_driver via686a_pci_driver = {
static int __init sm_via686a_init(void)
{
return pci_module_init(&via686a_pci_driver);
return pci_register_driver(&via686a_pci_driver);
}
static void __exit sm_via686a_exit(void)
......
......@@ -369,20 +369,20 @@ store_in_reg(MAX, max)
static ssize_t \
show_regs_in_##offset (struct device *dev, char *buf) \
{ \
return show_in(dev, buf, 0x##offset); \
return show_in(dev, buf, offset); \
} \
static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL);
#define sysfs_in_reg_offset(reg, offset) \
static ssize_t show_regs_in_##reg##offset (struct device *dev, char *buf) \
{ \
return show_in_##reg (dev, buf, 0x##offset); \
return show_in_##reg (dev, buf, offset); \
} \
static ssize_t \
store_regs_in_##reg##offset (struct device *dev, \
const char *buf, size_t count) \
{ \
return store_in_##reg (dev, buf, count, 0x##offset); \
return store_in_##reg (dev, buf, count, offset); \
} \
static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \
show_regs_in_##reg##offset, store_regs_in_##reg##offset);
......@@ -521,19 +521,19 @@ store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
#define sysfs_fan_offset(offset) \
static ssize_t show_regs_fan_##offset (struct device *dev, char *buf) \
{ \
return show_fan(dev, buf, 0x##offset); \
return show_fan(dev, buf, offset); \
} \
static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL);
#define sysfs_fan_min_offset(offset) \
static ssize_t show_regs_fan_min##offset (struct device *dev, char *buf) \
{ \
return show_fan_min(dev, buf, 0x##offset); \
return show_fan_min(dev, buf, offset); \
} \
static ssize_t \
store_regs_fan_min##offset (struct device *dev, const char *buf, size_t count) \
{ \
return store_fan_min(dev, buf, count, 0x##offset); \
return store_fan_min(dev, buf, count, offset); \
} \
static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
show_regs_fan_min##offset, store_regs_fan_min##offset);
......@@ -595,20 +595,20 @@ store_temp_reg(HYST, max_hyst);
static ssize_t \
show_regs_temp_##offset (struct device *dev, char *buf) \
{ \
return show_temp(dev, buf, 0x##offset); \
return show_temp(dev, buf, offset); \
} \
static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL);
#define sysfs_temp_reg_offset(reg, offset) \
static ssize_t show_regs_temp_##reg##offset (struct device *dev, char *buf) \
{ \
return show_temp_##reg (dev, buf, 0x##offset); \
return show_temp_##reg (dev, buf, offset); \
} \
static ssize_t \
store_regs_temp_##reg##offset (struct device *dev, \
const char *buf, size_t count) \
{ \
return store_temp_##reg (dev, buf, count, 0x##offset); \
return store_temp_##reg (dev, buf, count, offset); \
} \
static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \
show_regs_temp_##reg##offset, store_regs_temp_##reg##offset);
......@@ -845,7 +845,7 @@ store_regs_pwm_##offset (struct device *dev, const char *buf, size_t count) \
{ \
return store_pwm_reg(dev, buf, count, offset); \
} \
static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, \
static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
show_regs_pwm_##offset, store_regs_pwm_##offset);
sysfs_pwm(1);
......@@ -854,7 +854,7 @@ sysfs_pwm(3);
#define device_create_file_pwm(client, offset) \
do { \
device_create_file(&client->dev, &dev_attr_fan##offset##_pwm); \
device_create_file(&client->dev, &dev_attr_pwm##offset); \
} while (0)
static ssize_t
......
......@@ -318,18 +318,18 @@ store_in_reg(MAX, max);
static ssize_t \
show_regs_in_##offset (struct device *dev, char *buf) \
{ \
return show_in(dev, buf, 0x##offset); \
return show_in(dev, buf, offset); \
} \
static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL);
#define sysfs_in_reg_offset(reg, offset) \
static ssize_t show_regs_in_##reg##offset (struct device *dev, char *buf) \
{ \
return show_in_##reg (dev, buf, 0x##offset); \
return show_in_##reg (dev, buf, offset); \
} \
static ssize_t store_regs_in_##reg##offset (struct device *dev, const char *buf, size_t count) \
{ \
return store_in_##reg (dev, buf, count, 0x##offset); \
return store_in_##reg (dev, buf, count, offset); \
} \
static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset);
......@@ -384,18 +384,18 @@ store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
#define sysfs_fan_offset(offset) \
static ssize_t show_regs_fan_##offset (struct device *dev, char *buf) \
{ \
return show_fan(dev, buf, 0x##offset); \
return show_fan(dev, buf, offset); \
} \
static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL);
#define sysfs_fan_min_offset(offset) \
static ssize_t show_regs_fan_min##offset (struct device *dev, char *buf) \
{ \
return show_fan_min(dev, buf, 0x##offset); \
return show_fan_min(dev, buf, offset); \
} \
static ssize_t store_regs_fan_min##offset (struct device *dev, const char *buf, size_t count) \
{ \
return store_fan_min(dev, buf, count, 0x##offset); \
return store_fan_min(dev, buf, count, offset); \
} \
static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset);
......@@ -464,18 +464,18 @@ store_temp_reg(HYST, max_hyst);
static ssize_t \
show_regs_temp_##offset (struct device *dev, char *buf) \
{ \
return show_temp(dev, buf, 0x##offset); \
return show_temp(dev, buf, offset); \
} \
static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL);
#define sysfs_temp_reg_offset(reg, offset) \
static ssize_t show_regs_temp_##reg##offset (struct device *dev, char *buf) \
{ \
return show_temp_##reg (dev, buf, 0x##offset); \
return show_temp_##reg (dev, buf, offset); \
} \
static ssize_t store_regs_temp_##reg##offset (struct device *dev, const char *buf, size_t count) \
{ \
return store_temp_##reg (dev, buf, count, 0x##offset); \
return store_temp_##reg (dev, buf, count, offset); \
} \
static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset);
......@@ -740,22 +740,26 @@ static ssize_t show_regs_pwm_##offset (struct device *dev, char *buf) \
{ \
return show_pwm_reg(dev, buf, offset); \
} \
static ssize_t store_regs_pwm_##offset (struct device *dev, const char *buf, size_t count) \
static ssize_t store_regs_pwm_##offset (struct device *dev, \
const char *buf, size_t count) \
{ \
return store_pwm_reg(dev, buf, count, offset); \
} \
static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, show_regs_pwm_##offset, store_regs_pwm_##offset);
static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
show_regs_pwm_##offset, store_regs_pwm_##offset);
#define sysfs_pwmenable(offset) \
static ssize_t show_regs_pwmenable_##offset (struct device *dev, char *buf) \
{ \
return show_pwmenable_reg(dev, buf, offset); \
} \
static ssize_t store_regs_pwmenable_##offset (struct device *dev, const char *buf, size_t count) \
static ssize_t store_regs_pwmenable_##offset (struct device *dev, \
const char *buf, size_t count) \
{ \
return store_pwmenable_reg(dev, buf, count, offset); \
} \
static DEVICE_ATTR(fan##offset##_pwm_enable, S_IRUGO | S_IWUSR, show_regs_pwmenable_##offset, store_regs_pwmenable_##offset);
static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
show_regs_pwmenable_##offset, store_regs_pwmenable_##offset);
sysfs_pwm(1);
sysfs_pwm(2);
......@@ -765,12 +769,12 @@ sysfs_pwm(4);
#define device_create_file_pwm(client, offset) \
do { \
device_create_file(&client->dev, &dev_attr_fan##offset##_pwm); \
device_create_file(&client->dev, &dev_attr_pwm##offset); \
} while (0)
#define device_create_file_pwmenable(client, offset) \
do { \
device_create_file(&client->dev, &dev_attr_fan##offset##_pwm_enable); \
device_create_file(&client->dev, &dev_attr_pwm##offset##_enable); \
} while (0)
static ssize_t
......@@ -1062,6 +1066,9 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
if (is_isa)
if (!request_region(address, W83781D_EXTENT, "w83781d")) {
dev_dbg(&adapter->dev, "Request of region "
"0x%x-0x%x for w83781d failed\n", address,
address + W83781D_EXTENT - 1);
err = -EBUSY;
goto ERROR0;
}
......@@ -1075,15 +1082,11 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
/* 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) {
err = -ENODEV;
goto ERROR1;
}
if (inb_p(address + 3) != i) {
err = -ENODEV;
goto ERROR1;
}
if (inb_p(address + 7) != i) {
if (inb_p(address + 2) != i
|| inb_p(address + 3) != i
|| inb_p(address + 7) != i) {
dev_dbg(&adapter->dev, "Detection of w83781d "
"chip failed at step 1\n");
err = -ENODEV;
goto ERROR1;
}
......@@ -1092,8 +1095,13 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
/* 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)) {
val2 = inb_p(address + 5) & 0x7f;
if (val2 != (~i & 0x7f)) {
outb_p(i, address + 5);
dev_dbg(&adapter->dev, "Detection of w83781d "
"chip failed at step 2 (0x%x != "
"0x%x at 0x%x)\n", val2, ~i & 0x7f,
address + 5);
err = -ENODEV;
goto ERROR1;
}
......@@ -1125,7 +1133,9 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
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){
if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80) {
dev_dbg(&new_client->dev, "Detection failed at step "
"3\n");
err = -ENODEV;
goto ERROR2;
}
......@@ -1135,6 +1145,8 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
if ((!(val1 & 0x07)) &&
(((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3))
|| ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) {
dev_dbg(&new_client->dev, "Detection failed at step "
"4\n");
err = -ENODEV;
goto ERROR2;
}
......@@ -1144,6 +1156,8 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
((val1 & 0x80) && (val2 == 0x5c)))) {
if (w83781d_read_value
(new_client, W83781D_REG_I2C_ADDR) != address) {
dev_dbg(&new_client->dev, "Detection failed "
"at step 5\n");
err = -ENODEV;
goto ERROR2;
}
......@@ -1166,6 +1180,8 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
else if (val2 == 0x12)
vendid = asus;
else {
dev_dbg(&new_client->dev, "Chip was made by neither "
"Winbond nor Asus?\n");
err = -ENODEV;
goto ERROR2;
}
......@@ -1186,10 +1202,10 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
kind = w83697hf;
else {
if (kind == 0)
dev_warn(&new_client->dev,
"Ignoring 'force' parameter for unknown chip at"
"adapter %d, address 0x%02x\n",
i2c_adapter_id(adapter), address);
dev_warn(&new_client->dev, "Ignoring 'force' "
"parameter for unknown chip at "
"adapter %d, address 0x%02x\n",
i2c_adapter_id(adapter), address);
err = -EINVAL;
goto ERROR2;
}
......
......@@ -517,9 +517,29 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv)
return 1;
}
static int i2c_bus_suspend(struct device * dev, u32 state)
{
int rc = 0;
if (dev->driver && dev->driver->suspend)
rc = dev->driver->suspend(dev,state,0);
return rc;
}
static int i2c_bus_resume(struct device * dev)
{
int rc = 0;
if (dev->driver && dev->driver->resume)
rc = dev->driver->resume(dev,0);
return rc;
}
struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
.suspend = i2c_bus_suspend,
.resume = i2c_bus_resume,
};
static int __init i2c_init(void)
......
......@@ -2,6 +2,10 @@
# Makefile for the Dallas's 1-wire bus.
#
ifneq ($(CONFIG_NET), y)
EXTRA_CFLAGS += -DNETLINK_DISABLED
endif
obj-$(CONFIG_W1) += wire.o
wire-objs := w1.o w1_int.o w1_family.o w1_netlink.o w1_io.o
......
......@@ -727,12 +727,19 @@ void ds_disconnect(struct usb_interface *intf)
{
struct ds_device *dev;
dev = usb_get_intfdata (intf);
usb_set_intfdata (intf, NULL);
dev = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
while(atomic_read(&dev->refcnt))
while (atomic_read(&dev->refcnt)) {
printk(KERN_INFO "Waiting for DS to become free: refcnt=%d.\n",
atomic_read(&dev->refcnt));
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ);
if (signal_pending(current))
flush_signals(current);
}
usb_put_dev(dev->udev);
kfree(dev);
ds_dev = NULL;
......
......@@ -47,9 +47,11 @@ MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");
static int w1_timeout = 10;
int w1_max_slave_count = 10;
int w1_max_slave_ttl = 10;
module_param_named(timeout, w1_timeout, int, 0);
module_param_named(max_slave_count, w1_max_slave_count, int, 0);
module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);
spinlock_t w1_mlock = SPIN_LOCK_UNLOCKED;
LIST_HEAD(w1_masters);
......@@ -431,6 +433,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
return err;
}
sl->ttl = dev->slave_ttl;
dev->slave_count++;
memcpy(&msg.id.id, rn, sizeof(msg.id.id));
......@@ -446,8 +449,15 @@ static void w1_slave_detach(struct w1_slave *sl)
dev_info(&sl->dev, "%s: detaching %s.\n", __func__, sl->name);
while (atomic_read(&sl->refcnt))
schedule_timeout(10);
while (atomic_read(&sl->refcnt)) {
printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
sl->name, atomic_read(&sl->refcnt));
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ);
if (signal_pending(current))
flush_signals(current);
}
sysfs_remove_bin_file (&sl->dev.kobj, &sl->attr_bin);
device_remove_file(&sl->dev, &sl->attr_name);
......@@ -504,8 +514,8 @@ static void w1_search(struct w1_master *dev)
* All who don't sleep must send ID bit and COMPLEMENT ID bit.
* They actually are ANDed between all senders.
*/
id_bit = w1_read_bit(dev);
comp_bit = w1_read_bit(dev);
id_bit = w1_touch_bit(dev, 1);
comp_bit = w1_touch_bit(dev, 1);
if (id_bit && comp_bit)
break;
......@@ -536,7 +546,10 @@ static void w1_search(struct w1_master *dev)
* and make all who don't have "search_bit" in "i"'th position
* in it's registration number sleep.
*/
w1_write_bit(dev, search_bit);
if (dev->bus_master->touch_bit)
w1_touch_bit(dev, search_bit);
else
w1_write_bit(dev, search_bit);
}
#endif
......@@ -569,7 +582,7 @@ static void w1_search(struct w1_master *dev)
}
if (slave_count == dev->slave_count &&
((rn >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn, 7)) {
rn && ((rn >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn, 7)) {
w1_attach_slave_device(dev, (struct w1_reg_num *) &rn);
}
}
......@@ -718,7 +731,7 @@ int w1_process(void *data)
list_for_each_safe(ent, n, &dev->slist) {
sl = list_entry(ent, struct w1_slave, w1_slave_entry);
if (sl && !test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) {
if (sl && !test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) {
list_del (&sl->w1_slave_entry);
w1_slave_detach (sl);
......@@ -726,6 +739,8 @@ int w1_process(void *data)
dev->slave_count--;
}
else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags))
sl->ttl = dev->slave_ttl;
}
up(&dev->mutex);
}
......
......@@ -63,6 +63,7 @@ struct w1_slave
atomic_t refcnt;
u8 rom[9];
u32 flags;
int ttl;
struct w1_master *master;
struct w1_family *family;
......@@ -99,6 +100,7 @@ struct w1_master
struct list_head slist;
int max_slave_count, slave_count;
unsigned long attempts;
int slave_ttl;
int initialized;
u32 id;
......
......@@ -84,8 +84,15 @@ void w1_unregister_family(struct w1_family *fent)
spin_unlock(&w1_flock);
while (atomic_read(&fent->refcnt))
schedule_timeout(10);
while (atomic_read(&fent->refcnt)) {
printk(KERN_INFO "Waiting for family %u to become free: refcnt=%d.\n",
fent->fid, atomic_read(&fent->refcnt));
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ);
if (signal_pending(current))
flush_signals(current);
}
}
/*
......
......@@ -32,12 +32,13 @@ extern struct device_driver w1_driver;
extern struct bus_type w1_bus_type;
extern struct device w1_device;
extern int w1_max_slave_count;
extern int w1_max_slave_ttl;
extern struct list_head w1_masters;
extern spinlock_t w1_mlock;
extern int w1_process(void *);
struct w1_master * w1_alloc_dev(u32 id, int slave_count,
struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
struct device_driver *driver, struct device *device)
{
struct w1_master *dev;
......@@ -65,6 +66,7 @@ struct w1_master * w1_alloc_dev(u32 id, int slave_count,
dev->kpid = -1;
dev->initialized = 0;
dev->id = id;
dev->slave_ttl = slave_ttl;
atomic_set(&dev->refcnt, 2);
......@@ -121,7 +123,7 @@ int w1_add_master_device(struct w1_bus_master *master)
int retval = 0;
struct w1_netlink_msg msg;
dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, &w1_driver, &w1_device);
dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, w1_max_slave_ttl, &w1_driver, &w1_device);
if (!dev)
return -ENOMEM;
......@@ -179,8 +181,15 @@ void __w1_remove_master_device(struct w1_master *dev)
"%s: Failed to send signal to w1 kernel thread %d.\n",
__func__, dev->kpid);
while (atomic_read(&dev->refcnt))
schedule_timeout(10);
while (atomic_read(&dev->refcnt)) {
printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
dev->name, atomic_read(&dev->refcnt));
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ);
if (signal_pending(current))
flush_signals(current);
}
msg.id.mst.id = dev->id;
msg.id.mst.pid = dev->kpid;
......
......@@ -27,7 +27,7 @@
#include "w1.h"
struct w1_master * w1_alloc_dev(int, struct device_driver *, struct device *);
struct w1_master * w1_alloc_dev(u32, int, int, struct device_driver *, struct device *);
void w1_free_dev(struct w1_master *dev);
int w1_add_master_device(struct w1_bus_master *);
void w1_remove_master_device(struct w1_bus_master *);
......
......@@ -26,6 +26,7 @@
#include "w1_log.h"
#include "w1_netlink.h"
#ifndef NETLINK_DISABLED
void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
{
unsigned int size;
......@@ -53,3 +54,10 @@ void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
nlmsg_failure:
return;
}
#else
#warning Netlink support is disabled. Please compile with NET support enabled.
void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
{
}
#endif
......@@ -59,19 +59,28 @@ static ssize_t w1_therm_read_name(struct device *dev, char *buf)
return sprintf(buf, "%s\n", sl->name);
}
static inline int w1_convert_temp(u8 rom[9])
{
int t, h;
if (rom[1] == 0)
t = ((s32)rom[0] >> 1)*1000;
else
t = 1000*(-1*(s32)(0x100-rom[0]) >> 1);
t -= 250;
h = 1000*((s32)rom[7] - (s32)rom[6]);
h /= (s32)rom[7];
t += h;
return t;
}
static ssize_t w1_therm_read_temp(struct device *dev, char *buf)
{
struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
s16 temp;
/*
* Must be more precise.
*/
temp = 0;
temp <<= sl->rom[1] / 2;
temp |= sl->rom[0] / 2;
return sprintf(buf, "%d\n", temp * 1000);
return sprintf(buf, "%d\n", w1_convert_temp(sl->rom));
}
static int w1_therm_check_rom(u8 rom[9])
......@@ -92,7 +101,6 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si
struct w1_master *dev = sl->master;
u8 rom[9], crc, verdict;
int i, max_trying = 10;
u16 temp;
atomic_inc(&sl->refcnt);
if (down_interruptible(&sl->master->mutex)) {
......@@ -120,6 +128,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si
if (!w1_reset_bus (dev)) {
int count = 0;
u8 match[9] = {W1_MATCH_ROM, };
unsigned long tm;
memcpy(&match[1], (u64 *) & sl->reg_num, 8);
......@@ -127,24 +136,29 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si
w1_write_8(dev, W1_CONVERT_TEMP);
if (count < 10) {
if (!w1_reset_bus(dev)) {
w1_write_block(dev, match, 9);
w1_write_8(dev, W1_READ_SCRATCHPAD);
if ((count = w1_read_block(dev, rom, 9)) != 9) {
dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count);
}
tm = jiffies + msecs_to_jiffies(750);
while(time_before(jiffies, tm)) {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(tm-jiffies);
crc = w1_calc_crc8(rom, 8);
if (signal_pending(current))
flush_signals(current);
}
if (rom[8] == crc && rom[0])
verdict = 1;
if (!w1_reset_bus (dev)) {
w1_write_block(dev, match, 9);
w1_write_8(dev, W1_READ_SCRATCHPAD);
if ((count = w1_read_block(dev, rom, 9)) != 9) {
dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count);
}
crc = w1_calc_crc8(rom, 8);
if (rom[8] == crc && rom[0])
verdict = 1;
}
else
dev_warn(&dev->dev,
"18S20 doesn't respond to CONVERT_TEMP.\n");
}
if (!w1_therm_check_rom(rom))
......@@ -157,12 +171,13 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si
crc, (verdict) ? "YES" : "NO");
if (verdict)
memcpy(sl->rom, rom, sizeof(sl->rom));
else
dev_warn(&dev->dev, "18S20 doesn't respond to CONVERT_TEMP.\n");
for (i = 0; i < 9; ++i)
count += sprintf(buf + count, "%02x ", sl->rom[i]);
temp = 0;
temp <<= sl->rom[1] / 2;
temp |= sl->rom[0] / 2;
count += sprintf(buf + count, "t=%u\n", temp);
count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom));
out:
up(&dev->mutex);
out_dec:
......
......@@ -29,7 +29,22 @@
*/
/*
Legal val values 00 - 1F.
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 0x00 - 0x1f; 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.
......@@ -41,9 +56,28 @@ int i2c_which_vrm(void);
static inline int vid_from_reg(int val, int vrm)
{
int vid;
switch(vrm) {
case 0:
return 0;
case 100: /* VRD 10.0 */
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 */
return(val == 0x1f ? 0 : 1550 - val * 25);
case 91: /* VRM 9.1 */
case 90: /* VRM 9.0 */
return(val == 0x1f ? 0 :
......
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