URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [i2c/] [i2c-core.c] - Rev 1275
Go to most recent revision | Compare with Previous | Blame | View Log
/* i2c-core.c - a device driver for the iic-bus interface */ /* ------------------------------------------------------------------------- */ /* Copyright (C) 1995-99 Simon G. Vogl 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. */ /* ------------------------------------------------------------------------- */ /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>. All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> */ /* $Id: i2c-core.c,v 1.1.1.1 2004-04-15 01:38:25 phoenix Exp $ */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/slab.h> #include <linux/proc_fs.h> #include <linux/config.h> #include <linux/i2c.h> /* ----- compatibility stuff ----------------------------------------------- */ #include <linux/init.h> #include <asm/uaccess.h> /* ----- global defines ---------------------------------------------------- */ /* exclusive access to the bus */ #define I2C_LOCK(adap) down(&adap->lock) #define I2C_UNLOCK(adap) up(&adap->lock) #define ADAP_LOCK() down(&adap_lock) #define ADAP_UNLOCK() up(&adap_lock) #define DRV_LOCK() down(&driver_lock) #define DRV_UNLOCK() up(&driver_lock) #define DEB(x) if (i2c_debug>=1) x; #define DEB2(x) if (i2c_debug>=2) x; /* ----- global variables -------------------------------------------------- */ /**** lock for writing to global variables: the adapter & driver list */ struct semaphore adap_lock; struct semaphore driver_lock; /**** adapter list */ static struct i2c_adapter *adapters[I2C_ADAP_MAX]; static int adap_count; /**** drivers list */ static struct i2c_driver *drivers[I2C_DRIVER_MAX]; static int driver_count; /**** debug level */ static int i2c_debug=1; /* --------------------------------------------------- * /proc entry declarations *---------------------------------------------------- */ #ifdef CONFIG_PROC_FS static int i2cproc_init(void); static int i2cproc_cleanup(void); static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, loff_t *ppos); static int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof , void *private); /* To implement the dynamic /proc/bus/i2c-? files, we need our own implementation of the read hook */ static struct file_operations i2cproc_operations = { read: i2cproc_bus_read, }; static int i2cproc_initialized = 0; #else /* undef CONFIG_PROC_FS */ #define i2cproc_init() 0 #define i2cproc_cleanup() 0 #endif /* CONFIG_PROC_FS */ /* --------------------------------------------------- * registering functions * --------------------------------------------------- */ /* ----- * i2c_add_adapter is called from within the algorithm layer, * when a new hw adapter registers. A new device is register to be * available for clients. */ int i2c_add_adapter(struct i2c_adapter *adap) { int i,j,res; ADAP_LOCK(); for (i = 0; i < I2C_ADAP_MAX; i++) if (NULL == adapters[i]) break; if (I2C_ADAP_MAX == i) { printk(KERN_WARNING " i2c-core.o: register_adapter(%s) - enlarge I2C_ADAP_MAX.\n", adap->name); res = -ENOMEM; goto ERROR0; } adapters[i] = adap; adap_count++; ADAP_UNLOCK(); /* init data types */ init_MUTEX(&adap->lock); #ifdef CONFIG_PROC_FS if (i2cproc_initialized) { char name[8]; struct proc_dir_entry *proc_entry; sprintf(name,"i2c-%d", i); proc_entry = create_proc_entry(name,0,proc_bus); if (! proc_entry) { printk("i2c-core.o: Could not create /proc/bus/%s\n", name); res = -ENOENT; goto ERROR1; } proc_entry->proc_fops = &i2cproc_operations; proc_entry->owner = THIS_MODULE; adap->inode = proc_entry->low_ino; } #endif /* def CONFIG_PROC_FS */ /* inform drivers of new adapters */ DRV_LOCK(); for (j=0;j<I2C_DRIVER_MAX;j++) if (drivers[j]!=NULL && (drivers[j]->flags&(I2C_DF_NOTIFY|I2C_DF_DUMMY))) /* We ignore the return code; if it fails, too bad */ drivers[j]->attach_adapter(adap); DRV_UNLOCK(); DEB(printk(KERN_DEBUG "i2c-core.o: adapter %s registered as adapter %d.\n", adap->name,i)); return 0; ERROR1: ADAP_LOCK(); adapters[i] = NULL; adap_count--; ERROR0: ADAP_UNLOCK(); return res; } int i2c_del_adapter(struct i2c_adapter *adap) { int i,j,res; ADAP_LOCK(); for (i = 0; i < I2C_ADAP_MAX; i++) if (adap == adapters[i]) break; if (I2C_ADAP_MAX == i) { printk(KERN_WARNING "i2c-core.o: unregister_adapter adap [%s] not found.\n", adap->name); res = -ENODEV; goto ERROR0; } /* DUMMY drivers do not register their clients, so we have to * use a trick here: we call driver->attach_adapter to * *detach* it! Of course, each dummy driver should know about * this or hell will break loose... */ DRV_LOCK(); for (j = 0; j < I2C_DRIVER_MAX; j++) if (drivers[j] && (drivers[j]->flags & I2C_DF_DUMMY)) if ((res = drivers[j]->attach_adapter(adap))) { printk(KERN_WARNING "i2c-core.o: can't detach adapter %s " "while detaching driver %s: driver not " "detached!",adap->name,drivers[j]->name); goto ERROR1; } DRV_UNLOCK(); /* detach any active clients. This must be done first, because * it can fail; in which case we give upp. */ for (j=0;j<I2C_CLIENT_MAX;j++) { struct i2c_client *client = adap->clients[j]; if (client!=NULL) /* detaching devices is unconditional of the set notify * flag, as _all_ clients that reside on the adapter * must be deleted, as this would cause invalid states. */ if ((res=client->driver->detach_client(client))) { printk(KERN_ERR "i2c-core.o: adapter %s not " "unregistered, because client at " "address %02x can't be detached. ", adap->name, client->addr); goto ERROR0; } } #ifdef CONFIG_PROC_FS if (i2cproc_initialized) { char name[8]; sprintf(name,"i2c-%d", i); remove_proc_entry(name,proc_bus); } #endif /* def CONFIG_PROC_FS */ adapters[i] = NULL; adap_count--; ADAP_UNLOCK(); DEB(printk(KERN_DEBUG "i2c-core.o: adapter unregistered: %s\n",adap->name)); return 0; ERROR0: ADAP_UNLOCK(); return res; ERROR1: DRV_UNLOCK(); return res; } /* ----- * What follows is the "upwards" interface: commands for talking to clients, * which implement the functions to access the physical information of the * chips. */ int i2c_add_driver(struct i2c_driver *driver) { int i; DRV_LOCK(); for (i = 0; i < I2C_DRIVER_MAX; i++) if (NULL == drivers[i]) break; if (I2C_DRIVER_MAX == i) { printk(KERN_WARNING " i2c-core.o: register_driver(%s) " "- enlarge I2C_DRIVER_MAX.\n", driver->name); DRV_UNLOCK(); return -ENOMEM; } drivers[i] = driver; driver_count++; DRV_UNLOCK(); /* driver was successfully added */ DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name)); ADAP_LOCK(); /* now look for instances of driver on our adapters */ if (driver->flags& (I2C_DF_NOTIFY|I2C_DF_DUMMY)) { for (i=0;i<I2C_ADAP_MAX;i++) if (adapters[i]!=NULL) /* Ignore errors */ driver->attach_adapter(adapters[i]); } ADAP_UNLOCK(); return 0; } int i2c_del_driver(struct i2c_driver *driver) { int i,j,k,res; DRV_LOCK(); for (i = 0; i < I2C_DRIVER_MAX; i++) if (driver == drivers[i]) break; if (I2C_DRIVER_MAX == i) { printk(KERN_WARNING " i2c-core.o: unregister_driver: " "[%s] not found\n", driver->name); DRV_UNLOCK(); return -ENODEV; } /* Have a look at each adapter, if clients of this driver are still * attached. If so, detach them to be able to kill the driver * afterwards. */ DEB2(printk(KERN_DEBUG "i2c-core.o: unregister_driver - looking for clients.\n")); /* removing clients does not depend on the notify flag, else * invalid operation might (will!) result, when using stale client * pointers. */ ADAP_LOCK(); /* should be moved inside the if statement... */ for (k=0;k<I2C_ADAP_MAX;k++) { struct i2c_adapter *adap = adapters[k]; if (adap == NULL) /* skip empty entries. */ continue; DEB2(printk(KERN_DEBUG "i2c-core.o: examining adapter %s:\n", adap->name)); if (driver->flags & I2C_DF_DUMMY) { /* DUMMY drivers do not register their clients, so we have to * use a trick here: we call driver->attach_adapter to * *detach* it! Of course, each dummy driver should know about * this or hell will break loose... */ if ((res = driver->attach_adapter(adap))) { printk(KERN_WARNING "i2c-core.o: while unregistering " "dummy driver %s, adapter %s could " "not be detached properly; driver " "not unloaded!",driver->name, adap->name); ADAP_UNLOCK(); return res; } } else { for (j=0;j<I2C_CLIENT_MAX;j++) { struct i2c_client *client = adap->clients[j]; if (client != NULL && client->driver == driver) { DEB2(printk(KERN_DEBUG "i2c-core.o: " "detaching client %s:\n", client->name)); if ((res = driver-> detach_client(client))) { printk(KERN_ERR "i2c-core.o: while " "unregistering driver " "`%s', the client at " "address %02x of " "adapter `%s' could not" "be detached; driver" "not unloaded!", driver->name, client->addr, adap->name); ADAP_UNLOCK(); return res; } } } } } ADAP_UNLOCK(); drivers[i] = NULL; driver_count--; DRV_UNLOCK(); DEB(printk(KERN_DEBUG "i2c-core.o: driver unregistered: %s\n",driver->name)); return 0; } int i2c_check_addr (struct i2c_adapter *adapter, int addr) { int i; for (i = 0; i < I2C_CLIENT_MAX ; i++) if (adapter->clients[i] && (adapter->clients[i]->addr == addr)) return -EBUSY; return 0; } int i2c_attach_client(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; int i; if (i2c_check_addr(client->adapter,client->addr)) return -EBUSY; for (i = 0; i < I2C_CLIENT_MAX; i++) if (NULL == adapter->clients[i]) break; if (I2C_CLIENT_MAX == i) { printk(KERN_WARNING " i2c-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.\n", client->name); return -ENOMEM; } adapter->clients[i] = client; adapter->client_count++; if (adapter->client_register) if (adapter->client_register(client)) printk(KERN_DEBUG "i2c-core.o: warning: client_register seems " "to have failed for client %02x at adapter %s\n", client->addr,adapter->name); DEB(printk(KERN_DEBUG "i2c-core.o: client [%s] registered to adapter [%s](pos. %d).\n", client->name, adapter->name,i)); if(client->flags & I2C_CLIENT_ALLOW_USE) client->usage_count = 0; return 0; } int i2c_detach_client(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; int i,res; for (i = 0; i < I2C_CLIENT_MAX; i++) if (client == adapter->clients[i]) break; if (I2C_CLIENT_MAX == i) { printk(KERN_WARNING " i2c-core.o: unregister_client " "[%s] not found\n", client->name); return -ENODEV; } if( (client->flags & I2C_CLIENT_ALLOW_USE) && (client->usage_count>0)) return -EBUSY; if (adapter->client_unregister != NULL) if ((res = adapter->client_unregister(client))) { printk(KERN_ERR "i2c-core.o: client_unregister [%s] failed, " "client not detached",client->name); return res; } adapter->clients[i] = NULL; adapter->client_count--; DEB(printk(KERN_DEBUG "i2c-core.o: client [%s] unregistered.\n",client->name)); return 0; } void i2c_inc_use_client(struct i2c_client *client) { if (client->driver->inc_use != NULL) client->driver->inc_use(client); if (client->adapter->inc_use != NULL) client->adapter->inc_use(client->adapter); } void i2c_dec_use_client(struct i2c_client *client) { if (client->driver->dec_use != NULL) client->driver->dec_use(client); if (client->adapter->dec_use != NULL) client->adapter->dec_use(client->adapter); } struct i2c_client *i2c_get_client(int driver_id, int adapter_id, struct i2c_client *prev) { int i,j; /* Will iterate through the list of clients in each adapter of adapters-list in search for a client that matches the search criteria. driver_id or adapter_id are ignored if set to 0. If both are ignored this returns first client found. */ i = j = 0; /* set starting point */ if(prev) { if(!(prev->adapter)) return (struct i2c_client *) -EINVAL; for(j=0; j < I2C_ADAP_MAX; j++) if(prev->adapter == adapters[j]) break; /* invalid starting point? */ if (I2C_ADAP_MAX == j) { printk(KERN_WARNING " i2c-core.o: get_client adapter for client:[%s] not found\n", prev->name); return (struct i2c_client *) -ENODEV; } for(i=0; i < I2C_CLIENT_MAX; i++) if(prev == adapters[j]->clients[i]) break; /* invalid starting point? */ if (I2C_CLIENT_MAX == i) { printk(KERN_WARNING " i2c-core.o: get_client client:[%s] not found\n", prev->name); return (struct i2c_client *) -ENODEV; } i++; /* start from one after prev */ } for(; j < I2C_ADAP_MAX; j++) { if(!adapters[j]) continue; if(adapter_id && (adapters[j]->id != adapter_id)) continue; for(; i < I2C_CLIENT_MAX; i++) { if(!adapters[j]->clients[i]) continue; if(driver_id && (adapters[j]->clients[i]->driver->id != driver_id)) continue; if(adapters[j]->clients[i]->flags & I2C_CLIENT_ALLOW_USE) return adapters[j]->clients[i]; } i = 0; } return 0; } int i2c_use_client(struct i2c_client *client) { if(client->flags & I2C_CLIENT_ALLOW_USE) { if (client->flags & I2C_CLIENT_ALLOW_MULTIPLE_USE) client->usage_count++; else { if(client->usage_count > 0) return -EBUSY; else client->usage_count++; } } i2c_inc_use_client(client); return 0; } int i2c_release_client(struct i2c_client *client) { if(client->flags & I2C_CLIENT_ALLOW_USE) { if(client->usage_count>0) client->usage_count--; else { printk(KERN_WARNING " i2c-core.o: dec_use_client used one too many times\n"); return -EPERM; } } i2c_dec_use_client(client); return 0; } /* ---------------------------------------------------- * The /proc functions * ---------------------------------------------------- */ #ifdef CONFIG_PROC_FS /* This function generates the output for /proc/bus/i2c */ int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, void *private) { int i; int nr = 0; /* Note that it is safe to write a `little' beyond len. Yes, really. */ for (i = 0; (i < I2C_ADAP_MAX) && (nr < len); i++) if (adapters[i]) { nr += sprintf(buf+nr, "i2c-%d\t", i); if (adapters[i]->algo->smbus_xfer) { if (adapters[i]->algo->master_xfer) nr += sprintf(buf+nr,"smbus/i2c"); else nr += sprintf(buf+nr,"smbus "); } else if (adapters[i]->algo->master_xfer) nr += sprintf(buf+nr,"i2c "); else nr += sprintf(buf+nr,"dummy "); nr += sprintf(buf+nr,"\t%-32s\t%-32s\n", adapters[i]->name, adapters[i]->algo->name); } return nr; } /* This function generates the output for /proc/bus/i2c-? */ ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, loff_t *ppos) { struct inode * inode = file->f_dentry->d_inode; char *kbuf; struct i2c_client *client; int i,j,k,order_nr,len=0; size_t len_total; int order[I2C_CLIENT_MAX]; if (count > 4000) return -EINVAL; len_total = file->f_pos + count; /* Too bad if this gets longer (unlikely) */ if (len_total > 4000) len_total = 4000; for (i = 0; i < I2C_ADAP_MAX; i++) if (adapters[i]->inode == inode->i_ino) { /* We need a bit of slack in the kernel buffer; this makes the sprintf safe. */ if (! (kbuf = kmalloc(count + 80,GFP_KERNEL))) return -ENOMEM; /* Order will hold the indexes of the clients sorted by address */ order_nr=0; for (j = 0; j < I2C_CLIENT_MAX; j++) { if ((client = adapters[i]->clients[j]) && (client->driver->id != I2C_DRIVERID_I2CDEV)) { for(k = order_nr; (k > 0) && adapters[i]->clients[order[k-1]]-> addr > client->addr; k--) order[k] = order[k-1]; order[k] = j; order_nr++; } } for (j = 0; (j < order_nr) && (len < len_total); j++) { client = adapters[i]->clients[order[j]]; len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n", client->addr, client->name, client->driver->name); } len = len - file->f_pos; if (len > count) len = count; if (len < 0) len = 0; if (copy_to_user (buf,kbuf+file->f_pos, len)) { kfree(kbuf); return -EFAULT; } file->f_pos += len; kfree(kbuf); return len; } return -ENOENT; } int i2cproc_init(void) { struct proc_dir_entry *proc_bus_i2c; i2cproc_initialized = 0; if (! proc_bus) { printk("i2c-core.o: /proc/bus/ does not exist"); i2cproc_cleanup(); return -ENOENT; } proc_bus_i2c = create_proc_entry("i2c",0,proc_bus); if (!proc_bus_i2c) { printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/i2c"); i2cproc_cleanup(); return -ENOENT; } proc_bus_i2c->read_proc = &read_bus_i2c; proc_bus_i2c->owner = THIS_MODULE; i2cproc_initialized += 2; return 0; } int i2cproc_cleanup(void) { if (i2cproc_initialized >= 1) { remove_proc_entry("i2c",proc_bus); i2cproc_initialized -= 2; } return 0; } #endif /* def CONFIG_PROC_FS */ /* ---------------------------------------------------- * the functional interface to the i2c busses. * ---------------------------------------------------- */ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num) { int ret; if (adap->algo->master_xfer) { DEB2(printk(KERN_DEBUG "i2c-core.o: master_xfer: %s with %d msgs.\n", adap->name,num)); I2C_LOCK(adap); ret = adap->algo->master_xfer(adap,msgs,num); I2C_UNLOCK(adap); return ret; } else { printk(KERN_ERR "i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", adap->id); return -ENOSYS; } } int i2c_master_send(struct i2c_client *client,const char *buf ,int count) { int ret; struct i2c_adapter *adap=client->adapter; struct i2c_msg msg; if (client->adapter->algo->master_xfer) { msg.addr = client->addr; msg.flags = client->flags & I2C_M_TEN; msg.len = count; (const char *)msg.buf = buf; DEB2(printk(KERN_DEBUG "i2c-core.o: master_send: writing %d bytes on %s.\n", count,client->adapter->name)); I2C_LOCK(adap); ret = adap->algo->master_xfer(adap,&msg,1); I2C_UNLOCK(adap); /* if everything went ok (i.e. 1 msg transmitted), return #bytes * transmitted, else error code. */ return (ret == 1 )? count : ret; } else { printk(KERN_ERR "i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", client->adapter->id); return -ENOSYS; } } int i2c_master_recv(struct i2c_client *client, char *buf ,int count) { struct i2c_adapter *adap=client->adapter; struct i2c_msg msg; int ret; if (client->adapter->algo->master_xfer) { msg.addr = client->addr; msg.flags = client->flags & I2C_M_TEN; msg.flags |= I2C_M_RD; msg.len = count; msg.buf = buf; DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: reading %d bytes on %s.\n", count,client->adapter->name)); I2C_LOCK(adap); ret = adap->algo->master_xfer(adap,&msg,1); I2C_UNLOCK(adap); DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n", ret, count, client->addr)); /* if everything went ok (i.e. 1 msg transmitted), return #bytes * transmitted, else error code. */ return (ret == 1 )? count : ret; } else { printk(KERN_ERR "i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", client->adapter->id); return -ENOSYS; } } int i2c_control(struct i2c_client *client, unsigned int cmd, unsigned long arg) { int ret = 0; struct i2c_adapter *adap = client->adapter; DEB2(printk(KERN_DEBUG "i2c-core.o: i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg)); switch ( cmd ) { case I2C_RETRIES: adap->retries = arg; break; case I2C_TIMEOUT: adap->timeout = arg; break; default: if (adap->algo->algo_control!=NULL) ret = adap->algo->algo_control(adap,cmd,arg); } return ret; } /* ---------------------------------------------------- * the i2c address scanning function * Will not work for 10-bit addresses! * ---------------------------------------------------- */ int i2c_probe(struct i2c_adapter *adapter, struct i2c_client_address_data *address_data, i2c_client_found_addr_proc *found_proc) { int addr,i,found,err; int adap_id = i2c_adapter_id(adapter); /* Forget it if we can't probe using SMBUS_QUICK */ if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK)) return -1; for (addr = 0x00; addr <= 0x7f; addr++) { /* Skip if already in use */ if (i2c_check_addr(adapter,addr)) continue; /* If it is in one of the force entries, we don't do any detection at all */ found = 0; for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 3) { if (((adap_id == address_data->force[i]) || (address_data->force[i] == ANY_I2C_BUS)) && (addr == address_data->force[i+1])) { DEB2(printk(KERN_DEBUG "i2c-core.o: found force parameter for adapter %d, addr %04x\n", adap_id,addr)); if ((err = found_proc(adapter,addr,0,0))) return err; found = 1; } } if (found) continue; /* If this address is in one of the ignores, we can forget about it right now */ for (i = 0; !found && (address_data->ignore[i] != I2C_CLIENT_END); i += 2) { if (((adap_id == address_data->ignore[i]) || ((address_data->ignore[i] == ANY_I2C_BUS))) && (addr == address_data->ignore[i+1])) { DEB2(printk(KERN_DEBUG "i2c-core.o: found ignore parameter for adapter %d, " "addr %04x\n", adap_id ,addr)); found = 1; } } for (i = 0; !found && (address_data->ignore_range[i] != I2C_CLIENT_END); i += 3) { if (((adap_id == address_data->ignore_range[i]) || ((address_data->ignore_range[i]==ANY_I2C_BUS))) && (addr >= address_data->ignore_range[i+1]) && (addr <= address_data->ignore_range[i+2])) { DEB2(printk(KERN_DEBUG "i2c-core.o: found ignore_range parameter for adapter %d, " "addr %04x\n", adap_id,addr)); found = 1; } } if (found) continue; /* Now, we will do a detection, but only if it is in the normal or probe entries */ for (i = 0; !found && (address_data->normal_i2c[i] != I2C_CLIENT_END); i += 1) { if (addr == address_data->normal_i2c[i]) { found = 1; DEB2(printk(KERN_DEBUG "i2c-core.o: found normal i2c entry for adapter %d, " "addr %02x", adap_id,addr)); } } for (i = 0; !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END); i += 2) { if ((addr >= address_data->normal_i2c_range[i]) && (addr <= address_data->normal_i2c_range[i+1])) { found = 1; DEB2(printk(KERN_DEBUG "i2c-core.o: found normal i2c_range entry for adapter %d, " "addr %04x\n", adap_id,addr)); } } for (i = 0; !found && (address_data->probe[i] != I2C_CLIENT_END); i += 2) { if (((adap_id == address_data->probe[i]) || ((address_data->probe[i] == ANY_I2C_BUS))) && (addr == address_data->probe[i+1])) { found = 1; DEB2(printk(KERN_DEBUG "i2c-core.o: found probe parameter for adapter %d, " "addr %04x\n", adap_id,addr)); } } for (i = 0; !found && (address_data->probe_range[i] != I2C_CLIENT_END); i += 3) { if (((adap_id == address_data->probe_range[i]) || (address_data->probe_range[i] == ANY_I2C_BUS)) && (addr >= address_data->probe_range[i+1]) && (addr <= address_data->probe_range[i+2])) { found = 1; DEB2(printk(KERN_DEBUG "i2c-core.o: found probe_range parameter for adapter %d, " "addr %04x\n", adap_id,addr)); } } if (!found) continue; /* OK, so we really should examine this address. First check whether there is some client here at all! */ if (i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL) >= 0) if ((err = found_proc(adapter,addr,0,-1))) return err; } return 0; } /* * return id number for a specific adapter */ int i2c_adapter_id(struct i2c_adapter *adap) { int i; for (i = 0; i < I2C_ADAP_MAX; i++) if (adap == adapters[i]) return i; return -1; } /* The SMBus parts */ extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value) { return i2c_smbus_xfer(client->adapter,client->addr,client->flags, value,0,I2C_SMBUS_QUICK,NULL); } extern s32 i2c_smbus_read_byte(struct i2c_client * client) { union i2c_smbus_data data; if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_READ,0,I2C_SMBUS_BYTE, &data)) return -1; else return 0x0FF & data.byte; } extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value) { return i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL); } extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command) { union i2c_smbus_data data; if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data)) return -1; else return 0x0FF & data.byte; } extern s32 i2c_smbus_write_byte_data(struct i2c_client * client, u8 command, u8 value) { union i2c_smbus_data data; data.byte = value; return i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_WRITE,command, I2C_SMBUS_BYTE_DATA,&data); } extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command) { union i2c_smbus_data data; if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA, &data)) return -1; else return 0x0FFFF & data.word; } extern s32 i2c_smbus_write_word_data(struct i2c_client * client, u8 command, u16 value) { union i2c_smbus_data data; data.word = value; return i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_WRITE,command, I2C_SMBUS_WORD_DATA,&data); } extern s32 i2c_smbus_process_call(struct i2c_client * client, u8 command, u16 value) { union i2c_smbus_data data; data.word = value; if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_WRITE,command, I2C_SMBUS_PROC_CALL, &data)) return -1; else return 0x0FFFF & data.word; } /* Returns the number of read bytes */ extern s32 i2c_smbus_read_block_data(struct i2c_client * client, u8 command, u8 *values) { union i2c_smbus_data data; int i; if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_READ,command, I2C_SMBUS_BLOCK_DATA,&data)) return -1; else { for (i = 1; i <= data.block[0]; i++) values[i-1] = data.block[i]; return data.block[0]; } } extern s32 i2c_smbus_write_block_data(struct i2c_client * client, u8 command, u8 length, u8 *values) { union i2c_smbus_data data; int i; if (length > I2C_SMBUS_BLOCK_MAX) length = I2C_SMBUS_BLOCK_MAX; for (i = 1; i <= length; i++) data.block[i] = values[i-1]; data.block[0] = length; return i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_WRITE,command, I2C_SMBUS_BLOCK_DATA,&data); } extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client, u8 command, u8 length, u8 *values) { union i2c_smbus_data data; int i; if (length > I2C_SMBUS_I2C_BLOCK_MAX) length = I2C_SMBUS_I2C_BLOCK_MAX; for (i = 1; i <= length; i++) data.block[i] = values[i-1]; data.block[0] = length; return i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_WRITE,command, I2C_SMBUS_I2C_BLOCK_DATA,&data); } /* Simulate a SMBus command using the i2c protocol No checking of parameters is done! */ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data) { /* So we need to generate a series of msgs. In the case of writing, we need to use only one message; when reading, we need two. We initialize most things with sane defaults, to keep the code below somewhat simpler. */ unsigned char msgbuf0[34]; unsigned char msgbuf1[34]; int num = read_write == I2C_SMBUS_READ?2:1; struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, { addr, flags | I2C_M_RD, 0, msgbuf1 } }; int i; msgbuf0[0] = command; switch(size) { case I2C_SMBUS_QUICK: msg[0].len = 0; /* Special case: The read/write field is used as data */ msg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0; num = 1; break; case I2C_SMBUS_BYTE: if (read_write == I2C_SMBUS_READ) { /* Special case: only a read! */ msg[0].flags = I2C_M_RD | flags; num = 1; } break; case I2C_SMBUS_BYTE_DATA: if (read_write == I2C_SMBUS_READ) msg[1].len = 1; else { msg[0].len = 2; msgbuf0[1] = data->byte; } break; case I2C_SMBUS_WORD_DATA: if (read_write == I2C_SMBUS_READ) msg[1].len = 2; else { msg[0].len=3; msgbuf0[1] = data->word & 0xff; msgbuf0[2] = (data->word >> 8) & 0xff; } break; case I2C_SMBUS_PROC_CALL: num = 2; /* Special case */ msg[0].len = 3; msg[1].len = 2; msgbuf0[1] = data->word & 0xff; msgbuf0[2] = (data->word >> 8) & 0xff; break; case I2C_SMBUS_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { printk(KERN_ERR "i2c-core.o: Block read not supported " "under I2C emulation!\n"); return -1; } else { msg[0].len = data->block[0] + 2; if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { printk(KERN_ERR "i2c-core.o: smbus_access called with " "invalid block write size (%d)\n", data->block[0]); return -1; } for (i = 1; i <= msg[0].len; i++) msgbuf0[i] = data->block[i-1]; } break; default: printk(KERN_ERR "i2c-core.o: smbus_access called with invalid size (%d)\n", size); return -1; } if (i2c_transfer(adapter, msg, num) < 0) return -1; if (read_write == I2C_SMBUS_READ) switch(size) { case I2C_SMBUS_BYTE: data->byte = msgbuf0[0]; break; case I2C_SMBUS_BYTE_DATA: data->byte = msgbuf1[0]; break; case I2C_SMBUS_WORD_DATA: case I2C_SMBUS_PROC_CALL: data->word = msgbuf1[0] | (msgbuf1[1] << 8); break; } return 0; } 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) { s32 res; flags = flags & I2C_M_TEN; if (adapter->algo->smbus_xfer) { I2C_LOCK(adapter); res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, command,size,data); I2C_UNLOCK(adapter); } else res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, command,size,data); return res; } /* You should always define `functionality'; the 'else' is just for backward compatibility. */ u32 i2c_get_functionality (struct i2c_adapter *adap) { if (adap->algo->functionality) return adap->algo->functionality(adap); else return 0xffffffff; } int i2c_check_functionality (struct i2c_adapter *adap, u32 func) { u32 adap_func = i2c_get_functionality (adap); return (func & adap_func) == func; } static int __init i2c_init(void) { printk(KERN_INFO "i2c-core.o: i2c core module version %s (%s)\n", I2C_VERSION, I2C_DATE); memset(adapters,0,sizeof(adapters)); memset(drivers,0,sizeof(drivers)); adap_count=0; driver_count=0; init_MUTEX(&adap_lock); init_MUTEX(&driver_lock); i2cproc_init(); return 0; } #ifndef MODULE #ifdef CONFIG_I2C_CHARDEV extern int i2c_dev_init(void); #endif #ifdef CONFIG_I2C_ALGOBIT extern int i2c_algo_bit_init(void); #endif #ifdef CONFIG_I2C_PHILIPSPAR extern int i2c_bitlp_init(void); #endif #ifdef CONFIG_I2C_ELV extern int i2c_bitelv_init(void); #endif #ifdef CONFIG_I2C_VELLEMAN extern int i2c_bitvelle_init(void); #endif #ifdef CONFIG_I2C_BITVIA extern int i2c_bitvia_init(void); #endif #ifdef CONFIG_I2C_ALGOPCF extern int i2c_algo_pcf_init(void); #endif #ifdef CONFIG_I2C_ELEKTOR extern int i2c_pcfisa_init(void); #endif #ifdef CONFIG_I2C_ALGO8XX extern int i2c_algo_8xx_init(void); #endif #ifdef CONFIG_I2C_RPXLITE extern int i2c_rpx_init(void); #endif #ifdef CONFIG_I2C_ALGO_SIBYTE extern int i2c_algo_sibyte_init(void); extern int i2c_sibyte_init(void); #endif #ifdef CONFIG_I2C_MAX1617 extern int i2c_max1617_init(void); #endif #ifdef CONFIG_I2C_PROC extern int sensors_init(void); #endif /* This is needed for automatic patch generation: sensors code starts here */ /* This is needed for automatic patch generation: sensors code ends here */ int __init i2c_init_all(void) { /* --------------------- global ----- */ i2c_init(); #ifdef CONFIG_I2C_CHARDEV i2c_dev_init(); #endif /* --------------------- bit -------- */ #ifdef CONFIG_I2C_ALGOBIT i2c_algo_bit_init(); #endif #ifdef CONFIG_I2C_PHILIPSPAR i2c_bitlp_init(); #endif #ifdef CONFIG_I2C_ELV i2c_bitelv_init(); #endif #ifdef CONFIG_I2C_VELLEMAN i2c_bitvelle_init(); #endif /* --------------------- pcf -------- */ #ifdef CONFIG_I2C_ALGOPCF i2c_algo_pcf_init(); #endif #ifdef CONFIG_I2C_ELEKTOR i2c_pcfisa_init(); #endif /* --------------------- 8xx -------- */ #ifdef CONFIG_I2C_ALGO8XX i2c_algo_8xx_init(); #endif #ifdef CONFIG_I2C_RPXLITE i2c_rpx_init(); #endif /* --------------------- SiByte -------- */ #ifdef CONFIG_I2C_ALGO_SIBYTE i2c_algo_sibyte_init(); i2c_sibyte_init(); #endif #ifdef CONFIG_I2C_MAX1617 i2c_max1617_init(); #endif /* -------------- proc interface ---- */ #ifdef CONFIG_I2C_PROC sensors_init(); #endif /* This is needed for automatic patch generation: sensors code starts here */ /* This is needed for automatic patch generation: sensors code ends here */ return 0; } #endif EXPORT_SYMBOL(i2c_add_adapter); EXPORT_SYMBOL(i2c_del_adapter); EXPORT_SYMBOL(i2c_add_driver); EXPORT_SYMBOL(i2c_del_driver); EXPORT_SYMBOL(i2c_attach_client); EXPORT_SYMBOL(i2c_detach_client); EXPORT_SYMBOL(i2c_inc_use_client); EXPORT_SYMBOL(i2c_dec_use_client); EXPORT_SYMBOL(i2c_get_client); EXPORT_SYMBOL(i2c_use_client); EXPORT_SYMBOL(i2c_release_client); EXPORT_SYMBOL(i2c_check_addr); EXPORT_SYMBOL(i2c_master_send); EXPORT_SYMBOL(i2c_master_recv); EXPORT_SYMBOL(i2c_control); EXPORT_SYMBOL(i2c_transfer); EXPORT_SYMBOL(i2c_adapter_id); EXPORT_SYMBOL(i2c_probe); EXPORT_SYMBOL(i2c_smbus_xfer); EXPORT_SYMBOL(i2c_smbus_write_quick); EXPORT_SYMBOL(i2c_smbus_read_byte); EXPORT_SYMBOL(i2c_smbus_write_byte); EXPORT_SYMBOL(i2c_smbus_read_byte_data); EXPORT_SYMBOL(i2c_smbus_write_byte_data); EXPORT_SYMBOL(i2c_smbus_read_word_data); EXPORT_SYMBOL(i2c_smbus_write_word_data); EXPORT_SYMBOL(i2c_smbus_process_call); EXPORT_SYMBOL(i2c_smbus_read_block_data); EXPORT_SYMBOL(i2c_smbus_write_block_data); EXPORT_SYMBOL(i2c_get_functionality); EXPORT_SYMBOL(i2c_check_functionality); #ifdef MODULE MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>"); MODULE_DESCRIPTION("I2C-Bus main module"); MODULE_LICENSE("GPL"); MODULE_PARM(i2c_debug, "i"); MODULE_PARM_DESC(i2c_debug,"debug level"); int init_module(void) { return i2c_init(); } void cleanup_module(void) { i2cproc_cleanup(); } #endif
Go to most recent revision | Compare with Previous | Blame | View Log