patch-2.3.34 linux/Documentation/i2c/writing-clients
Next file: linux/Documentation/kernel-parameters.txt
Previous file: linux/Documentation/i2c/ten-bit-addresses
Back to the patch index
Back to the overall index
- Lines: 863
- Date:
Thu Dec 16 13:59:38 1999
- Orig file:
v2.3.33/linux/Documentation/i2c/writing-clients
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.3.33/linux/Documentation/i2c/writing-clients linux/Documentation/i2c/writing-clients
@@ -0,0 +1,862 @@
+This is a small guide for those who want to write kernel drivers for I2C
+or SMBus devices.
+
+To set up a driver, you need to do several things. Some are optional, and
+some things can be done slightly or completely different. Use this as a
+guide, not as a rule book!
+
+
+General remarks
+===============
+
+Try to keep the kernel namespace as clean as possible. The best way to
+do this is to use a unique prefix for all global symbols. This is
+especially important for exported symbols, but it is a good idea to do
+it for non-exported symbols too. We will use the prefix `foo_' in this
+tutorial, and `FOO_' for preprocessor variables.
+
+
+The driver structure
+====================
+
+Usually, you will implement a single driver structure, and instantiate
+all clients from it. Remember, a driver structure contains general access
+routines, a client structure specific information like the actual I2C
+address.
+
+ struct i2c_driver foo_driver
+ {
+ /* name */ "Foo version 2.3 and later driver",
+ /* id */ I2C_DRIVERID_FOO,
+ /* flags */ I2C_DF_NOTIFY,
+ /* attach_adapter */ &foo_attach_adapter,
+ /* detach_client */ &foo_detach_client,
+ /* command */ &foo_command, /* May be NULL */
+ /* inc_use */ &foo_inc_use, /* May be NULL */
+ /* dec_use */ &foo_dev_use /* May be NULL */
+ }
+
+The name can be choosen 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).
+
+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.
+This is almost always what you want.
+
+All other fields are for call-back functions which will be explained
+below.
+
+
+Module usage count
+==================
+
+If your driver can also be compiled as a module, there are moments at
+which the module can not be removed from memory. For example, when you
+are doing a lengthy transaction, or when you create a /proc directory,
+and some process has entered that directory (this last case is the
+main reason why these call-backs were introduced).
+
+To increase or decrease the module usage count, you can use the
+MOD_{INC,DEC}_USE_COUNT macros. They must be called from the module
+which needs to get its usage count changed; that is why each driver
+module has to implement its own callback.
+
+ void foo_inc_use (struct i2c_client *client)
+ {
+ #ifdef MODULE
+ MOD_INC_USE_COUNT;
+ #endif
+ }
+
+ void foo_dec_use (struct i2c_client *client)
+ {
+ #ifdef MODULE
+ MOD_DEC_USE_COUNT;
+ #endif
+ }
+
+Do not call these call-back functions directly; instead, use one of the
+following functions defined in i2c.h:
+ void i2c_inc_use_client(struct i2c_client *);
+ void i2c_dec_use_client(struct i2c_client *);
+
+You should *not* increase the module count just because a device is
+detected and a client created. This would make it impossible to remove
+an adapter driver!
+
+
+Extra client data
+=================
+
+The client structure has a special `data' field that can point to any
+structure at all. You can use this to keep client-specific data. You
+do not always need this, but especially for `sensors' drivers, it can
+be very useful.
+
+An example structure is below.
+
+ struct foo_data {
+ struct semaphore lock; /* For ISA access in `sensors' drivers. */
+ int sysctl_id; /* To keep the /proc directory entry for
+ `sensors' drivers. */
+ enum chips type; /* To keep the chips type for `sensors' drivers. */
+
+ /* Because the i2c bus is slow, it is often useful to cache the read
+ information of a chip for some time (for example, 1 or 2 seconds).
+ It depends of course on the device whether this is really worthwhile
+ or even sensible. */
+ struct semaphore update_lock; /* When we are reading lots of information,
+ another process should not update the
+ below information */
+ char valid; /* != 0 if the following fields are valid. */
+ unsigned long last_updated; /* In jiffies */
+ /* Add the read information here too */
+ };
+
+
+Accessing the client
+====================
+
+Let's say we have a valid client structure. At some time, we will need
+to gather information from the client, or write new information to the
+client. How we will export this information to user-space is less
+important at this moment (perhaps we do not need to do this at all for
+some obscure clients). But we need generic reading and writing routines.
+
+I have found it useful to define foo_read and foo_write function for this.
+For some cases, it will be easier to call the i2c functions directly,
+but many chips have some kind of register-value idea that can easily
+be encapsulated. Also, some chips have both ISA and I2C interfaces, and
+it useful to abstract from this (only for `sensors' drivers).
+
+The below functions are simple examples, and should not be copied
+literally.
+
+ int foo_read_value(struct i2c_client *client, u8 reg)
+ {
+ if (reg < 0x10) /* byte-sized register */
+ return i2c_smbus_read_byte_data(client,reg);
+ else /* word-sized register */
+ return i2c_smbus_read_word_data(client,reg);
+ }
+
+ int foo_write_value(struct i2c_client *client, u8 reg, u16 value)
+ {
+ if (reg == 0x10) /* Impossible to write - driver error! */ {
+ return -1;
+ else if (reg < 0x10) /* byte-sized register */
+ return i2c_smbus_write_byte_data(client,reg,value);
+ else /* word-sized register */
+ return i2c_smbus_write_word_data(client,reg,value);
+ }
+
+For sensors code, you may have to cope with ISA registers too. Something
+like the below often works. Note the locking!
+
+ int foo_read_value(struct i2c_client *client, u8 reg)
+ {
+ int res;
+ if (i2c_is_isa_client(client)) {
+ down(&(((struct foo_data *) (client->data)) -> lock));
+ outb_p(reg,client->addr + FOO_ADDR_REG_OFFSET);
+ res = inb_p(client->addr + FOO_DATA_REG_OFFSET);
+ up(&(((struct foo_data *) (client->data)) -> lock));
+ return res;
+ } else
+ return i2c_smbus_read_byte_data(client,reg);
+ }
+
+Writing is done the same way.
+
+
+Probing and attaching
+=====================
+
+Most i2c devices can be present on several i2c addresses; for some this
+is determined in hardware (by soldering some chip pins to Vcc or Ground),
+for others this can be changed in software (by writing to specific client
+registers). Some devices are usually on a specific address, but not always;
+and some are even more tricky. So you will probably need to scan several
+i2c addresses for your clients, and do some sort of detection to see
+whether it is actually a device supported by your driver.
+
+To give the user a maximum of possibilities, some default module parameters
+are defined to help determine what addresses are scanned. Several macros
+are defined in i2c.h to help you support them, as well as a generic
+detection algorithm.
+
+You do not have to use this parameter interface; but don't try to use
+function i2c_probe() (or sensors_detect()) if you don't.
+
+NOTE: If you want to write a `sensors' driver, the interface is slightly
+ different! See below.
+
+
+
+Probing classes (i2c)
+---------------------
+
+All parameters are given as lists of unsigned 16-bit integers. Lists are
+terminated by I2C_CLIENT_END.
+The following lists are used internally:
+
+ normal_i2c: filled in by the module writer.
+ A list of I2C addresses which should normally be examined.
+ normal_i2c_range: filled in by the module writer.
+ A list of pairs of I2C addresses, each pair being an inclusive range of
+ addresses which should normally be examined.
+ probe: insmod parameter.
+ A list of pairs. The first value is a bus number (-1 for any I2C bus),
+ the second is the address. These addresses are also probed, as if they
+ were in the 'normal' list.
+ probe_range: insmod parameter.
+ A list of triples. The first value is a bus number (-1 for any I2C bus),
+ the second and third are addresses. These form an inclusive range of
+ addresses that are also probed, as if they were in the 'normal' list.
+ ignore: insmod parameter.
+ A list of pairs. The first value is a bus number (-1 for any I2C bus),
+ the second is the I2C address. These addresses are never probed.
+ This parameter overrules 'normal' and 'probe', but not the 'force' lists.
+ ignore_range: insmod parameter.
+ A list of triples. The first value is a bus number (-1 for any I2C bus),
+ the second and third are addresses. These form an inclusive range of
+ I2C addresses that are never probed.
+ This parameter overrules 'normal' and 'probe', but not the 'force' lists.
+ force: insmod parameter.
+ A list of pairs. The first value is a bus number (-1 for any I2C bus),
+ the second is the I2C address. A device is blindly assumed to be on
+ the given address, no probing is done.
+
+Fortunately, as a module writer, you just have to define the `normal'
+and/or `normal_range' parameters. The complete declaration could look
+like this:
+
+ /* Scan 0x20 to 0x2f, 0x37, and 0x40 to 0x4f */
+ static unsigned short normal_i2c[] = { 0x37,I2C_CLIENT_END };
+ static unsigned short normal_i2c_range[] = { 0x20, 0x2f, 0x40, 0x4f,
+ I2C_CLIENT_END };
+
+ /* Magic definition of all other variables and things */
+ I2C_CLIENT_INSMOD;
+
+Note that you *have* to call the two defined variables `normal_i2c' and
+`normal_i2c_range', without any prefix!
+
+
+Probing classes (sensors)
+-------------------------
+
+If you write a `sensors' driver, you use a slightly different interface.
+As well as I2C addresses, we have to cope with ISA addresses. Also, we
+use a enum of chip types. Don't forget to include `sensors.h'.
+
+The following lists are used internally. They are all lists of integers.
+
+ normal_i2c: filled in by the module writer. Terminated by SENSORS_I2C_END.
+ A list of I2C addresses which should normally be examined.
+ normal_i2c_range: filled in by the module writer. Terminated by
+ SENSORS_I2C_END
+ A list of pairs of I2C addresses, each pair being an inclusive range of
+ addresses which should normally be examined.
+ normal_isa: filled in by the module writer. Terminated by SENSORS_ISA_END.
+ A list of ISA addresses which should normally be examined.
+ normal_isa_range: filled in by the module writer. Terminated by
+ SENSORS_ISA_END
+ A list of triples. The first two elements are ISA addresses, being an
+ range of addresses which should normally be examined. The third is the
+ modulo parameter: only addresses which are 0 module this value relative
+ to the first address of the range are actually considered.
+ probe: insmod parameter. Initialize this list with SENSORS_I2C_END values.
+ A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for
+ the ISA bus, -1 for any I2C bus), the second is the address. These
+ addresses are also probed, as if they were in the 'normal' list.
+ probe_range: insmod parameter. Initialize this list with SENSORS_I2C_END
+ values.
+ A list of triples. The first value is a bus number (SENSORS_ISA_BUS for
+ the ISA bus, -1 for any I2C bus), the second and third are addresses.
+ These form an inclusive range of addresses that are also probed, as
+ if they were in the 'normal' list.
+ ignore: insmod parameter. Initialize this list with SENSORS_I2C_END values.
+ A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for
+ the ISA bus, -1 for any I2C bus), the second is the I2C address. These
+ addresses are never probed. This parameter overrules 'normal' and
+ 'probe', but not the 'force' lists.
+ ignore_range: insmod parameter. Initialize this list with SENSORS_I2C_END
+ values.
+ A list of triples. The first value is a bus number (SENSORS_ISA_BUS for
+ the ISA bus, -1 for any I2C bus), the second and third are addresses.
+ These form an inclusive range of I2C addresses that are never probed.
+ This parameter overrules 'normal' and 'probe', but not the 'force' lists.
+
+Also used is a list of pointers to sensors_force_data structures:
+ force_data: insmod parameters. A list, ending with an element of which
+ the force field is NULL.
+ Each element contains the type of chip and a list of pairs.
+ The first value is a bus number (SENSORS_ISA_BUS for the ISA bus,
+ -1 for any I2C bus), the second is the address.
+ These are automatically translated to insmod variables of the form
+ force_foo.
+
+So we have a generic insmod variabled `force', and chip-specific variables
+`force_CHIPNAME'.
+
+Fortunately, as a module writer, you just have to define the `normal'
+and/or `normal_range' parameters, and define what chip names are used.
+The complete declaration could look like this:
+ /* Scan i2c addresses 0x20 to 0x2f, 0x37, and 0x40 to 0x4f
+ static unsigned short normal_i2c[] = {0x37,SENSORS_I2C_END};
+ static unsigned short normal_i2c_range[] = {0x20,0x2f,0x40,0x4f,
+ SENSORS_I2C_END};
+ /* Scan ISA address 0x290 */
+ static unsigned int normal_isa[] = {0x0290,SENSORS_ISA_END};
+ static unsigned int normal_isa_range[] = {SENSORS_ISA_END};
+
+ /* Define chips foo and bar, as well as all module parameters and things */
+ SENSORS_INSMOD_2(foo,bar);
+
+If you have one chip, you use macro SENSORS_INSMOD_1(chip), if you have 2
+you use macro SENSORS_INSMOD_2(chip1,chip2), etc. If you do not want to
+bother with chip types, you can use SENSORS_INSMOD_0.
+
+A enum is automatically defined as follows:
+ enum chips { any_chip, chip1, chip2, ... }
+
+
+Attaching to an adapter
+-----------------------
+
+Whenever a new adapter is inserted, or for all adapters if the driver is
+being registered, the callback attach_adapter() is called. Now is the
+time to determine what devices are present on the adapter, and to register
+a client for each of them.
+
+The attach_adapter callback is really easy: we just call the generic
+detection function. This function will scan the bus for us, using the
+information as defined in the lists explained above. If a device is
+detected at a specific address, another callback is called.
+
+ int foo_attach_adapter(struct i2c_adapter *adapter)
+ {
+ return i2c_probe(adapter,&addr_data,&foo_detect_client);
+ }
+
+For `sensors' drivers, use the sensors_detect function instead:
+
+ int foo_attach_adapter(struct i2c_adapter *adapter)
+ {
+ return sensors_detect(adapter,&addr_data,&foo_detect_client);
+ }
+
+Remember, structure `addr_data' is defined by the macros explained above,
+so you do not have to define it yourself.
+
+The i2c_probe or sensors_detect function will call the foo_detect_client
+function only for those i2c addresses that actually have a device on
+them (unless a `force' parameter was used).
+
+
+The detect client function
+--------------------------
+
+The detect client function is called by i2c_probe or sensors_detect.
+The `kind' parameter contains 0 if this call is due to a `force'
+parameter, and 0 otherwise (for sensors_detect, it contains 0 if
+this call is due to the generic `force' parameter, and the chip type
+number if it is due to a specific `force' parameter).
+
+Below, some things are only needed if this is a `sensors' driver. Those
+parts are between /* SENSORS ONLY START */ and /* SENSORS ONLY END */
+markers.
+
+This function should only return an error (any value != 0) if there is
+some reason why no more detection should be done anymore. If the
+detection just fails for this address, return 0.
+
+For now, you can ignore the `flags' parameter. It is there for future use.
+
+ /* Unique ID allocation */
+ static int foo_id = 0;
+
+ int foo_detect_client(struct i2c_adapter *adapter, int address,
+ unsigned short flags, int kind)
+ {
+ int err = 0;
+ int i;
+ struct i2c_client *new_client;
+ struct foo_data *data;
+ const char *client_name = ""; /* For non-`sensors' drivers, put the real
+ name here! */
+
+ /* Let's see whether this adapter can support what we need.
+ Please substitute the things you need here!
+ For `sensors' drivers, add `! is_isa &&' to the if statement */
+ if (i2c_check_functionality(adapter,I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_WRITE_BYTE))
+ goto ERROR0;
+
+ /* SENSORS ONLY START */
+ const char *type_name = "";
+ int is_isa = i2c_is_isa_adapter(adapter);
+
+ if (is_isa) {
+
+ /* If this client can't be on the ISA bus at all, we can stop now
+ (call `goto ERROR0'). But for kicks, we will assume it is all
+ right. */
+
+ /* Discard immediately if this ISA range is already used */
+ if (check_region(address,FOO_EXTENT))
+ goto ERROR0;
+
+ /* Probe whether there is anything on this address.
+ Some example code is below, but you will have to adapt this
+ for your own driver */
+
+ if (kind < 0) /* Only if no force parameter was used */ {
+ /* We may need long timeouts at least for some chips. */
+ #define REALLY_SLOW_IO
+ i = inb_p(address + 1);
+ if (inb_p(address + 2) != i)
+ goto ERROR0;
+ if (inb_p(address + 3) != i)
+ goto ERROR0;
+ if (inb_p(address + 7) != i)
+ goto ERROR0;
+ #undef REALLY_SLOW_IO
+
+ /* Let's just hope nothing breaks here */
+ i = inb_p(address + 5) & 0x7f;
+ outb_p(~i & 0x7f,address+5);
+ if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) {
+ outb_p(i,address+5);
+ return 0;
+ }
+ }
+ }
+
+ /* SENSORS ONLY END */
+
+ /* OK. For now, we presume we have a valid client. We now create the
+ client structure, even though we cannot fill it completely yet.
+ But it allows us to access several i2c functions safely */
+
+ /* Note that we reserve some space for foo_data too. If you don't
+ need it, remove it. We do it here to help to lessen memory
+ fragmentation. */
+ if (! (new_client = kmalloc(sizeof(struct i2c_client)) +
+ sizeof(struct foo_data),
+ GFP_KERNEL)) {
+ err = -ENOMEM;
+ goto ERROR0;
+ }
+
+ /* This is tricky, but it will set the data to the right value. */
+ client->data = new_client + 1;
+ data = (struct foo_data *) (client->data);
+
+ new_client->addr = address;
+ new_client->data = data;
+ new_client->adapter = adapter;
+ new_client->driver = &foo_driver;
+ new_client->flags = 0;
+
+ /* Now, we do the remaining detection. If no `force' parameter is used. */
+
+ /* First, the generic detection (if any), that is skipped if any force
+ parameter was used. */
+ if (kind < 0) {
+ /* The below is of course bogus */
+ if (foo_read(new_client,FOO_REG_GENERIC) != FOO_GENERIC_VALUE)
+ goto ERROR1;
+ }
+
+ /* SENSORS ONLY START */
+
+ /* Next, specific detection. This is especially important for `sensors'
+ devices. */
+
+ /* Determine the chip type. Not needed if a `force_CHIPTYPE' parameter
+ was used. */
+ if (kind <= 0) {
+ i = foo_read(new_client,FOO_REG_CHIPTYPE);
+ if (i == FOO_TYPE_1)
+ kind = chip1; /* As defined in the enum */
+ else if (i == FOO_TYPE_2)
+ kind = chip2;
+ else {
+ printk("foo: Ignoring 'force' parameter for unknown chip at "
+ "adapter %d, address 0x%02x\n",i2c_adapter_id(adapter),address);
+ goto ERROR1;
+ }
+ }
+
+ /* Now set the type and chip names */
+ if (kind == chip1) {
+ type_name = "chip1"; /* For /proc entry */
+ client_name = "CHIP 1";
+ } else if (kind == chip2) {
+ type_name = "chip2"; /* For /proc entry */
+ client_name = "CHIP 2";
+ }
+
+ /* Reserve the ISA region */
+ if (is_isa)
+ request_region(address,FOO_EXTENT,type_name);
+
+ /* SENSORS ONLY END */
+
+ /* Fill in the remaining client fields. */
+ strcpy(new_client->name,client_name);
+
+ /* SENSORS ONLY BEGIN */
+ data->type = kind;
+ /* SENSORS ONLY END */
+
+ new_client->id = foo_id++; /* Automatically unique */
+ data->valid = 0; /* Only if you use this field */
+ init_MUTEX(&data->update_lock); /* Only if you use this field */
+
+ /* Any other initializations in data must be done here too. */
+
+ /* Tell the i2c layer a new client has arrived */
+ if ((err = i2c_attach_client(new_client)))
+ goto ERROR3;
+
+ /* SENSORS ONLY BEGIN */
+ /* Register a new directory entry with module sensors. See below for
+ the `template' structure. */
+ if ((i = sensors_register_entry(new_client, type_name,
+ foo_dir_table_template,THIS_MODULE)) < 0) {
+ err = i;
+ goto ERROR4;
+ }
+ data->sysctl_id = i;
+
+ /* SENSORS ONLY END */
+
+ /* This function can write default values to the client registers, if
+ needed. */
+ foo_init_client(new_client);
+ return 0;
+
+ /* OK, this is not exactly good programming practice, usually. But it is
+ very code-efficient in this case. */
+
+ ERROR4:
+ i2c_detach_client(new_client);
+ ERROR3:
+ ERROR2:
+ /* SENSORS ONLY START */
+ if (is_isa)
+ release_region(address,FOO_EXTENT);
+ /* SENSORS ONLY END */
+ ERROR1:
+ kfree(new_client);
+ ERROR0:
+ return err;
+ }
+
+
+Removing the client
+===================
+
+The detach_client call back function is called when a client should be
+removed. It may actually fail, but only when panicking. This code is
+much simpler than the attachment code, fortunately!
+
+ int foo_detach_client(struct i2c_client *client)
+ {
+ int err,i;
+
+ /* SENSORS ONLY START */
+ /* Deregister with the `sensors' module. */
+ sensors_deregister_entry(((struct lm78_data *)(client->data))->sysctl_id);
+ /* SENSORS ONLY END */
+
+ /* Try to detach the client from i2c space */
+ if ((err = i2c_detach_client(client))) {
+ printk("foo.o: Client deregistration failed, client not detached.\n");
+ return err;
+ }
+
+ /* SENSORS ONLY START */
+ if i2c_is_isa_client(client)
+ release_region(client->addr,LM78_EXTENT);
+ /* SENSORS ONLY END */
+
+ kfree(client); /* Frees client data too, if allocated at the same time */
+ return 0;
+ }
+
+
+Initializing the module or kernel
+=================================
+
+When the kernel is booted, or when your foo driver module is inserted,
+you have to do some initializing. Fortunately, just attaching (registering)
+the driver module is usually enough.
+
+ /* Keep track of how far we got in the initialization process. If several
+ things have to initialized, and we fail halfway, only those things
+ have to be cleaned up! */
+ static int __initdata foo_initialized = 0;
+
+ int __init foo_init(void)
+ {
+ int res;
+ printk("foo version %s (%s)\n",FOO_VERSION,FOO_DATE);
+
+ if ((res = i2c_add_driver(&foo_driver))) {
+ printk("foo: Driver registration failed, module not inserted.\n");
+ foo_cleanup();
+ return res;
+ }
+ foo_initialized ++;
+ return 0;
+ }
+
+ int __init foo_cleanup(void)
+ {
+ int res;
+ if (foo_initialized == 1) {
+ if ((res = i2c_del_driver(&foo_driver))) {
+ printk("foo: Driver registration failed, module not removed.\n");
+ return res;
+ }
+ foo_initialized --;
+ }
+ return 0;
+ }
+
+ #ifdef MODULE
+
+ /* Substitute your own name and email address */
+ MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"
+ MODULE_DESCRIPTION("Driver for Barf Inc. Foo I2C devices");
+
+ int init_module(void)
+ {
+ return foo_init();
+ }
+
+ int cleanup_module(void)
+ {
+ return foo_cleanup();
+ }
+
+ #endif /* def MODULE */
+
+Note that some functions are marked by `__init', and some data structures
+by `__init_data'. If this driver is compiled as part of the kernel (instead
+of as a module), those functions and structures can be removed after
+kernel booting is completed.
+
+Command function
+================
+
+A generic ioctl-like function call back is supported. You will seldomly
+need this. You may even set it to NULL.
+
+ /* No commands defined */
+ int foo_command(struct i2c_client *client, unsigned int cmd, void *arg)
+ {
+ return 0;
+ }
+
+You should never directly call this function, but instead use the
+general function below:
+
+ extern int i2c_control(struct i2c_client *,unsigned int, unsigned long);
+
+
+
+Sending and receiving
+=====================
+
+If you want to communicate with your device, there are several functions
+to do this. You can find all of them in i2c.h.
+
+If you can choose between plain i2c communication and SMBus level
+communication, please use the last. All adapters understand SMBus level
+commands, but only some of them understand plain i2c!
+
+
+Plain i2c communication
+-----------------------
+
+ extern int i2c_master_send(struct i2c_client *,const char* ,int);
+ extern int i2c_master_recv(struct i2c_client *,char* ,int);
+
+These routines read and write some bytes from/to a client. The client
+contains the i2c address, so you do not have to include it. The second
+parameter contains the bytes the read/write, the third the length of the
+buffer. Returned is the actual number of bytes read/written.
+
+ extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num);
+
+This sends a series of messages. Each message can be a read or write,
+and they can be mixed in any way. The transactions are combined: no
+stop bit is sent between transaction. The i2c_msg structure contains
+for each message the client address, the number of bytes of the message
+and the message data itself.
+
+You can read the file `i2c-protocol' for more information about the
+actual i2c protocol.
+
+
+SMBus communication
+-------------------
+
+ extern s32 i2c_smbus_xfer (struct i2c_adapter * adapter, u16 addr,
+ unsigned short flags,
+ char read_write, u8 command, int size,
+ union i2c_smbus_data * data);
+
+ This is the generic SMBus function. All functions below are implemented
+ in terms of it. Never use this function directly!
+
+
+ extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value);
+ extern s32 i2c_smbus_read_byte(struct i2c_client * client);
+ extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value);
+ extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command);
+ extern s32 i2c_smbus_write_byte_data(struct i2c_client * client,
+ u8 command, u8 value);
+ extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command);
+ extern s32 i2c_smbus_write_word_data(struct i2c_client * client,
+ u8 command, u16 value);
+ extern s32 i2c_smbus_process_call(struct i2c_client * client,
+ u8 command, u16 value);
+ extern s32 i2c_smbus_read_block_data(struct i2c_client * client,
+ u8 command, u8 *values);
+ extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
+ u8 command, u8 length,
+ u8 *values);
+
+All these tranactions return -1 on failure. The 'write' transactions
+return 0 on success; the 'read' transactions return the read value, except
+for read_block, which returns the number of values read. The block buffers
+need not be longer than 32 bytes.
+
+You can read the file `smbus-protocol' for more information about the
+actual SMBus protocol.
+
+
+General purpose routines
+========================
+
+Below all general purpose routines are listed, that were not mentioned
+before.
+
+ /* This call returns a unique low identifier for each registered adapter,
+ * or -1 if the adapter was not regisitered.
+ */
+ extern int i2c_adapter_id(struct i2c_adapter *adap);
+
+
+The sensors sysctl/proc interface
+=================================
+
+This section only applies if you write `sensors' drivers.
+
+Each sensors driver creates a directory in /proc/sys/dev/sensors for each
+registered client. The directory is called something like foo-i2c-4-65.
+The sensors module helps you to do this as easily as possible.
+
+The template
+------------
+
+You will need to define a ctl_table template. This template will automatically
+be copied to a newly allocated structure and filled in where necessary when
+you call sensors_register_entry.
+
+First, I will give an example definition.
+ static ctl_table foo_dir_table_template[] = {
+ { FOO_SYSCTL_FUNC1, "func1", NULL, 0, 0644, NULL, &sensors_proc_real,
+ &sensors_sysctl_real,NULL,&foo_func },
+ { FOO_SYSCTL_FUNC2, "func2", NULL, 0, 0644, NULL, &sensors_proc_real,
+ &sensors_sysctl_real,NULL,&foo_func },
+ { FOO_SYSCTL_DATA, "data", NULL, 0, 0644, NULL, &sensors_proc_real,
+ &sensors_sysctl_real,NULL,&foo_data },
+ { 0 }
+ };
+
+In the above example, three entries are defined. They can either be
+accessed through the /proc interface, in the /proc/sys/dev/sensors/*
+directories, as files named func1, func2 and data, or alternatively
+through the sysctl interface, in the appropriate table, with identifiers
+FOO_SYSCTL_FUNC1, FOO_SYSCTL_FUNC2 and FOO_SYSCTL_DATA.
+
+The third, sixth and ninth parameters should always be NULL, and the
+fourth should always be 0. The fifth is the mode of the /proc file;
+0644 is safe, as the file will be owned by root:root.
+
+The seventh and eigth parameters should be &sensors_proc_real and
+&sensors_sysctl_real if you want to export lists of reals (scaled
+integers). You can also use your own function for them, as usual.
+Finally, the last parameter is the call-back to gather the data
+(see below) if you use the *_proc_real functions.
+
+
+Gathering the data
+------------------
+
+The call back functions (foo_func and foo_data in the above example)
+can be called in several ways; the operation parameter determines
+what should be done:
+
+ * If operation == SENSORS_PROC_REAL_INFO, you must return the
+ magnitude (scaling) in nrels_mag;
+ * If operation == SENSORS_PROC_REAL_READ, you must read information
+ from the chip and return it in results. The number of integers
+ to display should be put in nrels_mag;
+ * If operation == SENSORS_PROC_REAL_WRITE, you must write the
+ supplied information to the chip. nrels_mag will contain the number
+ of integers, results the integers themselves.
+
+The *_proc_real functions will display the elements as reals for the
+/proc interface. If you set the magnitude to 2, and supply 345 for
+SENSORS_PROC_REAL_READ, it would display 3.45; and if the user would
+write 45.6 to the /proc file, it would be returned as 4560 for
+SENSORS_PROC_REAL_WRITE. A magnitude may even be negative!
+
+An example function:
+
+ /* FOO_FROM_REG and FOO_TO_REG translate between scaled values and
+ register values. Note the use of the read cache. */
+ void foo_in(struct i2c_client *client, int operation, int ctl_name,
+ int *nrels_mag, long *results)
+ {
+ struct foo_data *data = client->data;
+ int nr = ctl_name - FOO_SYSCTL_FUNC1; /* reduce to 0 upwards */
+
+ if (operation == SENSORS_PROC_REAL_INFO)
+ *nrels_mag = 2;
+ else if (operation == SENSORS_PROC_REAL_READ) {
+ /* Update the readings cache (if necessary) */
+ foo_update_client(client);
+ /* Get the readings from the cache */
+ results[0] = FOO_FROM_REG(data->foo_func_base[nr]);
+ results[1] = FOO_FROM_REG(data->foo_func_more[nr]);
+ results[2] = FOO_FROM_REG(data->foo_func_readonly[nr]);
+ *nrels_mag = 2;
+ } else if (operation == SENSORS_PROC_REAL_WRITE) {
+ if (*nrels_mag >= 1) {
+ /* Update the cache */
+ data->foo_base[nr] = FOO_TO_REG(results[0]);
+ /* Update the chip */
+ foo_write_value(client,FOO_REG_FUNC_BASE(nr),data->foo_base[nr]);
+ }
+ if (*nrels_mag >= 2) {
+ /* Update the cache */
+ data->foo_more[nr] = FOO_TO_REG(results[1]);
+ /* Update the chip */
+ foo_write_value(client,FOO_REG_FUNC_MORE(nr),data->foo_more[nr]);
+ }
+ }
+ }
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)