diff --git a/CHANGES b/CHANGES index 18d789c4..7430caea 100644 --- a/CHANGES +++ b/CHANGES @@ -18,6 +18,7 @@ ask CVS about it: ----------------------------------------------------------------------------- 2.6.3 (2002????) + Chip modules (most): Allow THIS_MODULE definition for kernels 2.2.18+ File doc/chips/it87: add more temp_type help File sensors.conf.eg: Un-ignore it87 in8, temp3, fan3; add adm1021 section; add lm87 AIN[1,2] template; @@ -34,11 +35,14 @@ ask CVS about it: Module i2c-amd756: Add support for AMD768 Module i2c-i810: Add support for 810E Module i2c-piix4: Check for uninitialized base address + Module i2c-sis5595: Blacklist 735 Module i2c-viapro: Check for uninitialized base address Module gl518sm: Standardize /proc entries in0-3 Module lm87: Fix in0, in1, in5 initial limits; ain[1,2] -> in[6,7]; fan -> fan1; fix temp2 limit writes + Module pcf8574: Add support for PCF8574A; /proc interface changed Module pcf8591: new + Module sis5595: Blacklist 735 Module w83781d: Add W83697HF support; allow force_subclients parameter for Tyan 2460 Program decode-vaio.pl: new diff --git a/doc/chips/SUMMARY b/doc/chips/SUMMARY index bee69c61..f0e41433 100644 --- a/doc/chips/SUMMARY +++ b/doc/chips/SUMMARY @@ -162,7 +162,7 @@ ltc1710 matorb Matrix Orbital LCD displays -pcf8574 +pcf8574 & pcf8574a Simple eight-bit parallel I/O pcf8591 diff --git a/doc/chips/pcf8574 b/doc/chips/pcf8574 new file mode 100644 index 00000000..06b4b82d --- /dev/null +++ b/doc/chips/pcf8574 @@ -0,0 +1,97 @@ +Kernel driver `pcf8574.o' +======================== + +Status: Status: Complete; + +Supported chips: + * Philips PCF8574 + Prefix: `pcf8574' + Addresses scanned: I2C 0x20 - 0x27 (inclusive) + Datasheet: Publicly available at the Philips Semiconductor website + http://semiconductors.philips.com/ + + * Philips PCF8574A + Prefix: `pcf8574a' + Addresses scanned: I2C 0x38 - 0x3f (inclusive) + Datasheet: Publicly available at the Philips Semiconductor website + http://semiconductors.philips.com/ + + +Authors: Frodo Looijaard , Philip Edelbrock , +and Dan Eaton + +Module Parameters +----------------- + +* force: short array (min = 1, max = 48) + List of adapter,address pairs to boldly assume to be present +* force_pcf8574: short array (min = 1, max = 48) + List of adapter,address pairs which are unquestionably assumed to + contain a `pcf8574' chip +* ignore: short array (min = 1, max = 48) + List of adapter,address pairs not to scan +* ignore_range: short array (min = 1, max = 48) + List of adapter,start-addr,end-addr triples not to scan +* probe: short array (min = 1, max = 48) + List of adapter,address pairs to scan additionally +* probe_range: short array (min = 1, max = 48) + List of adapter,start-addr,end-addr triples to scan additionally + + +Description +----------- +The PCF8574(A) is an 8-bit I/O expander for the I2C bus produced by Philips +Semiconductors. It is designed to provide a byte I2C interface to up to 16 +separate devices (8 x PCF8574 and 8 x PCF8574A). + +This device consists of a quasi-bidirectionnal port. Each of the eight I/Os +can be independently used as an input or output. To setup an I/O as an +input, you have to write a 1 to the corresponding output. + +For more informations see the datasheet. + + +Accessing PCF8574(A) via /proc interface +------------------------------------- + +! Be careful ! +The PCF8574(A) is plainly impossible to detect ! Stupid chip. +So every chip with adress in the interval [20..27] and (38..3f) are +detected as PCF8574(A). If you have other chips in this address +range, the workaround is to load this module after the one +for your others chips. + +On detection (i.e. insmod, modprobe et al.), directories are being +created for each detected PCF8574(A): + +/proc/sys/dev/sensors/pcf8574-<0>-<1>/ +where <0> is the bus the chip was detected on (e. g. i2c-0) +and <1> the chip address ([20..27] or [38..3f]): +./pcf8574-i2c-0-27/ + +Inside these directories, there are two files each: +read and write. + +The read file is read-only. Reading gives you the current I/O input +if the corresponding output is set as 1, otherwise the current output +value, that is to say 0. + +The write file is read/write. Writing a value outputs it on the I/O +port. Reading return the last written value. + +On module initialization the chip is configured as eight I/Os input (all +outputs to 1), so you can connect any circuit to the PCF8574(A) without +to be afraid of short-circuit. + + +Chip Features +------------- + +Chip `pcf8574' + LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE + read NONE NONE R 0 + write NONE NONE RW 0 + + LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET + read SENSORS_PCF8591_READ read:1 + write SENSORS_PCF8591_WRITE write:1 diff --git a/kernel/chips/pcf8574.c b/kernel/chips/pcf8574.c index ba4ddafc..6f9ade1b 100644 --- a/kernel/chips/pcf8574.c +++ b/kernel/chips/pcf8574.c @@ -61,19 +61,19 @@ MODULE_LICENSE("GPL"); /* Addresses to scan */ static unsigned short normal_i2c[] = { SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { 0x20, 0x27, SENSORS_I2C_END }; +static unsigned short normal_i2c_range[] = { 0x20, 0x27, 0x38, 0x3f, SENSORS_I2C_END }; static unsigned int normal_isa[] = { SENSORS_ISA_END }; static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; /* Insmod parameters */ -SENSORS_INSMOD_1(pcf8574); +SENSORS_INSMOD_2(pcf8574, pcf8574a); /* The PCF8574 registers */ /* (No registers. [Wow! This thing is SIMPLE!] ) */ /* Initial values */ -#define PCF8574_INIT 0 /* Both off */ +#define PCF8574_INIT 255 /* All outputs on (input mode) */ /* Each client has this additional data */ struct pcf8574_data { @@ -83,7 +83,7 @@ struct pcf8574_data { char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ - u8 status; /* Register values */ + u8 read, write; /* Register values */ }; #ifdef MODULE @@ -106,10 +106,12 @@ static int pcf8574_command(struct i2c_client *client, unsigned int cmd, void *arg); static void pcf8574_inc_use(struct i2c_client *client); static void pcf8574_dec_use(struct i2c_client *client); -static void pcf8574_status(struct i2c_client *client, int operation, +static void pcf8574_read(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void pcf8574_write(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); static void pcf8574_update_client(struct i2c_client *client); - +static void pcf8574_init_client(struct i2c_client *client); /* This is the driver that will be inserted */ static struct i2c_driver pcf8574_driver = { @@ -129,8 +131,10 @@ static struct i2c_driver pcf8574_driver = { is done through one of the 'extra' fields which are initialized when a new copy is allocated. */ static ctl_table pcf8574_dir_table_template[] = { - {PCF8574_SYSCTL_STAT, "status", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &pcf8574_status}, + {PCF8574_SYSCTL_READ, "read", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &pcf8574_read}, + {PCF8574_SYSCTL_WRITE, "write", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &pcf8574_write}, {0} }; @@ -190,13 +194,22 @@ int pcf8574_detect(struct i2c_adapter *adapter, int address, /* Now, we would do the remaining detection. But the PCF8574 is plainly impossible to detect! Stupid chip. */ - /* Determine the chip type - only one kind supported! */ - if (kind <= 0) - kind = pcf8574; + /* Determine the chip type */ + if (kind <= 0) { + if (address >= 0x20 && address <= 0x27) + kind = pcf8574; + else if (address >= 0x38 && address <= 0x3f) + kind = pcf8574a; + else goto ERROR1; + } if (kind == pcf8574) { type_name = "pcf8574"; client_name = "PCF8574 chip"; + } else + if (kind == pcf8574a) { + type_name = "pcf8574a"; + client_name = "PCF8574A chip"; } else { #ifdef DEBUG printk("pcf8574.o: Internal error: unknown kind (%d)?!?", @@ -225,6 +238,8 @@ int pcf8574_detect(struct i2c_adapter *adapter, int address, } data->sysctl_id = i; + /* Initialize the PCF8574 chip */ + pcf8574_init_client(new_client); return 0; /* OK, this is not exactly good programming practice, usually. But it is @@ -281,6 +296,14 @@ void pcf8574_dec_use(struct i2c_client *client) #endif } +/* Called when we have found a new PCF8574. */ +void pcf8574_init_client(struct i2c_client *client) +{ + struct pcf8574_data *data = client->data; + data->write = PCF8574_INIT; + i2c_smbus_write_byte(client, data->write); +} + void pcf8574_update_client(struct i2c_client *client) { @@ -295,7 +318,7 @@ void pcf8574_update_client(struct i2c_client *client) printk("Starting pcf8574 update\n"); #endif - data->status = i2c_smbus_read_byte(client); + data->read = i2c_smbus_read_byte(client); data->last_updated = jiffies; data->valid = 1; } @@ -304,7 +327,19 @@ void pcf8574_update_client(struct i2c_client *client) } -void pcf8574_status(struct i2c_client *client, int operation, +void pcf8574_read(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct pcf8574_data *data = client->data; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + pcf8574_update_client(client); + results[0] = data->read; + *nrels_mag = 1; + } +} +void pcf8574_write(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { u8 tmpstatus; @@ -313,22 +348,17 @@ void pcf8574_status(struct i2c_client *client, int operation, if (operation == SENSORS_PROC_REAL_INFO) *nrels_mag = 0; else if (operation == SENSORS_PROC_REAL_READ) { - pcf8574_update_client(client); - tmpstatus = data->status; - tmpstatus = (tmpstatus & 0xf0) >> 4; - results[0] = tmpstatus; - tmpstatus = data->status; - tmpstatus &= 0x0f; - results[1] = tmpstatus; - *nrels_mag = 2; + results[0] = data->write; + *nrels_mag = 1; } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->status = (data->status & 2) | results[0]; - i2c_smbus_write_byte(client, data->status); + if (*nrels_mag = 1) { + data->write = results[0]; + i2c_smbus_write_byte(client, data->write); } } } + int __init sensors_pcf8574_init(void) { int res; @@ -366,7 +396,7 @@ EXPORT_NO_SYMBOLS; #ifdef MODULE MODULE_AUTHOR - ("Frodo Looijaard , Philip Edelbrock "); + ("Frodo Looijaard , Philip Edelbrock , Dan Eaton and Aurelien Jarno "); MODULE_DESCRIPTION("PCF8574 driver"); int init_module(void) diff --git a/kernel/chips/pcf8591.c b/kernel/chips/pcf8591.c index bf4e7b3b..be9d067f 100644 --- a/kernel/chips/pcf8591.c +++ b/kernel/chips/pcf8591.c @@ -200,7 +200,7 @@ int pcf8591_detect(struct i2c_adapter *adapter, int address, #ifdef DEBUG if (i2c_is_isa_adapter(adapter)) { printk - (KERN_ERR "pcf8574.o: pcf8574_detect called for an ISA bus adapter?!?\n"); + (KERN_ERR "pcf8591.o: pcf8591_detect called for an ISA bus adapter?!?\n"); return 0; } #endif @@ -224,7 +224,7 @@ int pcf8591_detect(struct i2c_adapter *adapter, int address, new_client->driver = &pcf8591_driver; new_client->flags = 0; - /* Now, we would do the remaining detection. But the PCF8574 is plainly + /* Now, we would do the remaining detection. But the PCF8591 is plainly impossible to detect! Stupid chip. */ /* Determine the chip type - only one kind supported! */ diff --git a/kernel/include/sensors.h b/kernel/include/sensors.h index c4bfdf88..b042f75e 100644 --- a/kernel/include/sensors.h +++ b/kernel/include/sensors.h @@ -431,7 +431,8 @@ #define LM87_ALARM_TEMP2_FAULT 0x4000 #define LM87_ALARM_TEMP3_FAULT 0x08000 -#define PCF8574_SYSCTL_STAT 1000 +#define PCF8574_SYSCTL_READ 1000 +#define PCF8574_SYSCTL_WRITE 1001 #define MTP008_SYSCTL_IN0 1000 /* Volts * 100 */ #define MTP008_SYSCTL_IN1 1001