⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c-core.c

📁 linux下S3C2410的I2C总线的驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 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鰏ti M鋖kki <kmalkki@cc.hut.fi>.   All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> *//* $Id: i2c-core.c,v 1.2 2004/02/06 13:19:45 laputa 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/version.h>#include <linux/init.h>#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)#define init_MUTEX(s) do { *(s) = MUTEX; } while(0)#endif#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 = 0;/* --------------------------------------------------- * /proc entry declarations *---------------------------------------------------- */#ifdef CONFIG_PROC_FSstatic int i2cproc_init(void);static void i2cproc_cleanup(void);#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27))static void monitor_bus_i2c(struct inode *inode, int fill);#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */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,};#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,48))static struct inode_operations i2cproc_inode_operations = {	&i2cproc_operations};#endifstatic 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;		}#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,48))		proc_entry->proc_fops = &i2cproc_operations;#else		proc_entry->ops = &i2cproc_inode_operations;#endif#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27))		proc_entry->owner = THIS_MODULE;#else		proc_entry->fill_inode = &monitor_bus_i2c;#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */		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("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( "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("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("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("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("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("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("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("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("i2c-core.o: "						    "detaching client %s:\n",					            client->name));					if ((res = driver->							detach_client(client)))					{						printk("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("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("i2c-core.o: warning: client_register seems "			       "to have failed for client %02x at adapter %s\n",			       client->addr,adapter->name);	DEB(printk("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])

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -