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

📄 i2c-gm-adap.c

📁 基于GM8180,NSF2200F的I2C驱动,LINUX平台
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/smp_lock.h>

#include <linux/devfs_fs_kernel.h>

#include <linux/init.h>

#include <asm/uaccess.h>

#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/errno.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/i2c-algo-bit.h>
#include "i2c-algo-GM.h"
#define I2C_GM_ADAP_Version	"0.1"
#define Display_ID	0x88
#include <asm/arch/platform/spec.h>


/* exclusive access to the bus */
//#define I2C_LOCK(adap) down(&adap->clist_lock);
//#define I2C_UNLOCK(adap) up(&adap->clist_lock)

#define I2C_LOCK(adap) 
#define I2C_UNLOCK(adap) 


#define I2C_HW_GM 0x15	/* GM I2C interface */
#ifdef CONFIG_PLATFORM_GM8120
#define CRYSTALL_FREQ	22118400
#else
#define CRYSTALL_FREQ	12288000
#endif

#define I2C_MAX_FREQ	(400 * 1024)
#define I2C_Default_FREQ	(45 * 1024)

#define BIT2			0x04
	#define BIT0			0x01
	#define BIT1			0x02
	#define BIT2			0x04
	#define BIT3			0x08
	#define BIT4			0x10
	#define BIT5			0x20
	#define BIT6			0x40
	#define BIT7			0x80
	#define BIT8			0x0100
	#define BIT9			0x0200
	#define BIT10			0x0400
	#define BIT11			0x0800
	#define BIT12			0x1000
	#define BIT13			0x2000
	#define BIT14			0x4000
	#define BIT15			0x8000
	#define BIT16			0x010000
	#define BIT17			0x020000
	#define BIT18			0x040000
	#define BIT19			0x080000
	#define BIT20			0x100000
	#define BIT21			0x200000
	#define BIT22			0x400000
	#define BIT23			0x800000
	#define BIT24			0x01000000
	#define BIT25			0x02000000
	#define BIT26			0x04000000
	#define BIT27			0x08000000
	#define BIT28			0x10000000
	#define BIT29			0x20000000
	#define BIT30			0x40000000
#define I2C_GSR_Value		0x00
#define I2C_TSR_Value		0x20
#define I2C_CDR_Value		0x40	  // when pclk == 22.1184 MHz ==> i2c_clk = 173k

/* I2C Register */
#define I2C_Control                     0x0
#define I2C_Status                      0x4
#define I2C_ClockDiv                    0x8
#define I2C_Data                        0x0C
#define I2C_SlaveAddr                   0x10
#define I2C_TGSR                        0x14  /* 2003/05/28 Correct by Peter */
#define I2C_BMR                         0x18  /* 2003/05/28 Correct by Peter */

extern int iic_xfer(struct i2c_adapter *i2c_adap,struct i2c_msg msgs[],int num);
		    
static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, 
                            loff_t *offset);
static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count, 
                             loff_t *offset);

static int i2cdev_ioctl(struct inode *inode, struct file *file,
		unsigned int cmd, unsigned *arg);
		//unsigned int cmd, unsigned long arg);                         
static int i2cdev_open (struct inode *inode, struct file *file);
static int i2cdev_release (struct inode *inode, struct file *file);

static void i2cdev_cleanup(void);

static int i2ctv_attach_adapter(struct i2c_adapter *adap);
static int i2cdev_detach_client(struct i2c_client *client);
static int i2cdev_command(struct i2c_client *client, unsigned int cmd,void *arg);

static struct i2c_client i2cdev_client_template;
struct i2c_dev {
	int minor;
	struct i2c_adapter *adap;
	struct class_device class_dev;
	struct completion released;	/* FIXME, we need a class_device_unregister() */
};
#define to_i2c_dev(d) container_of(d, struct i2c_dev, class_dev)

#define I2C_MINORS	256
static struct i2c_dev *i2c_dev_array[I2C_MINORS];
static DEFINE_SPINLOCK(i2c_dev_array_lock);

static struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
{
	struct i2c_dev *i2c_dev;

	spin_lock(&i2c_dev_array_lock);
	i2c_dev = i2c_dev_array[index];
	spin_unlock(&i2c_dev_array_lock);
	return i2c_dev;
}

static struct i2c_dev *i2c_dev_get_by_adapter(struct i2c_adapter *adap)
{
	struct i2c_dev *i2c_dev = NULL;

	spin_lock(&i2c_dev_array_lock);
	if ((i2c_dev_array[adap->nr]) &&
	    (i2c_dev_array[adap->nr]->adap == adap))
		i2c_dev = i2c_dev_array[adap->nr];
	spin_unlock(&i2c_dev_array_lock);
	return i2c_dev;
}

static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap)
{
	struct i2c_dev *i2c_dev;

	i2c_dev = kmalloc(sizeof(*i2c_dev), GFP_KERNEL);
	if (!i2c_dev)
		return ERR_PTR(-ENOMEM);
	memset(i2c_dev, 0x00, sizeof(*i2c_dev));

	spin_lock(&i2c_dev_array_lock);
	if (i2c_dev_array[adap->nr]) {
		spin_unlock(&i2c_dev_array_lock);
		dev_err(&adap->dev, "i2c-dev already has a device assigned to this adapter\n");
		goto error;
	}
	i2c_dev->minor = adap->nr;
	i2c_dev_array[adap->nr] = i2c_dev;
	spin_unlock(&i2c_dev_array_lock);
	return i2c_dev;
error:
	kfree(i2c_dev);
	return ERR_PTR(-ENODEV);
}

static void return_i2c_dev(struct i2c_dev *i2c_dev)
{
	spin_lock(&i2c_dev_array_lock);
	i2c_dev_array[i2c_dev->minor] = NULL;
	spin_unlock(&i2c_dev_array_lock);
}

static ssize_t show_adapter_name(struct class_device *class_dev, char *buf)
{
	struct i2c_dev *i2c_dev = to_i2c_dev(class_dev);
	return sprintf(buf, "%s\n", i2c_dev->adap->name);
}

static CLASS_DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);

static struct file_operations i2cdev_fops = {
	.owner		= THIS_MODULE,
	.llseek		= no_llseek,
	.read		= i2cdev_read,
	.write		= i2cdev_write,
	.ioctl		= i2cdev_ioctl,
	.open		= i2cdev_open,
	.release	= i2cdev_release,
};

static void release_i2c_dev(struct class_device *dev)
{
	struct i2c_dev *i2c_dev = to_i2c_dev(dev);
	complete(&i2c_dev->released);
}

static struct class i2c_dev_class = {
	.name		= "i2c-dev",
	.release	= &release_i2c_dev,
};

static int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
	struct i2c_dev *i2c_dev;
	int retval;

	i2c_dev = get_free_i2c_dev(adap);
	if (IS_ERR(i2c_dev))
		return PTR_ERR(i2c_dev);

	devfs_mk_cdev(MKDEV(I2C_MAJOR, i2c_dev->minor),
			S_IFCHR|S_IRUSR|S_IWUSR, "i2c/%d", i2c_dev->minor);
	printk("i2c-dev: adapter [%s] registered as minor %d\n",
		 adap->name, i2c_dev->minor);

	/* register this i2c device with the driver core */
	i2c_dev->adap = adap;
	if (adap->dev.parent == &platform_bus)
		i2c_dev->class_dev.dev = &adap->dev;
	else
		i2c_dev->class_dev.dev = adap->dev.parent;
	i2c_dev->class_dev.class = &i2c_dev_class;
	i2c_dev->class_dev.devt = MKDEV(I2C_MAJOR, i2c_dev->minor);
	snprintf(i2c_dev->class_dev.class_id, BUS_ID_SIZE, "i2c-%d", i2c_dev->minor);
	retval = class_device_register(&i2c_dev->class_dev);
	if (retval)
		goto error;
	class_device_create_file(&i2c_dev->class_dev, &class_device_attr_name);
	return 0;
error:
	return_i2c_dev(i2c_dev);
	kfree(i2c_dev);
	return retval;
}

static int i2cdev_detach_adapter(struct i2c_adapter *adap)
{
	struct i2c_dev *i2c_dev;

	i2c_dev = i2c_dev_get_by_adapter(adap);
	if (!i2c_dev)
		return -ENODEV;

	init_completion(&i2c_dev->released);
	devfs_remove("i2c/%d", i2c_dev->minor);
	return_i2c_dev(i2c_dev);
	class_device_unregister(&i2c_dev->class_dev);
	wait_for_completion(&i2c_dev->released);
	kfree(i2c_dev);

	pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
	return 0;
}

static int i2cdev_detach_client(struct i2c_client *client)
{
	return 0;
}

static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
                           void *arg)
{
	return -1;
}

static struct i2c_driver i2cdev_driver = {
	.owner		= THIS_MODULE,
	.name		= "i2c-dev driver",
	.id		= I2C_DRIVERID_TUNER,
	.flags		= I2C_DF_NOTIFY,
	.attach_adapter	= i2cdev_attach_adapter,
	.detach_adapter	= i2cdev_detach_adapter,
	.detach_client	= i2cdev_detach_client,
	.command	= i2cdev_command,
};


static struct i2c_client i2cdev_client_template = {
	.name		= "I2C /dev entry",
	.addr		= -1,
	.driver		= &i2cdev_driver,
};

static int i2cdev_initialized;

//#define DEBUG 1
//#include "../../arch/arm/mach-cpe/cfg.h"
#define IDENTIFIER0  0x30
#define IDENTIFIER1  0x32

struct cfg_t
{
    unsigned char identifier0;      //offset 0, IDENTIFIER0
    unsigned char identifier1;      //offset 1, IDENTIFIER1
    unsigned char reserved0[3];
    unsigned char ic_version[10];   //offset 5
    unsigned char evb_version[10];  //offset 15
    unsigned char soft_version[10]; //offset 25
    unsigned char reserved1[10];    //offset 35
    unsigned char ahb_clk;          //offset 45
    unsigned char reserved4[19];    
    unsigned char mac[6];           //offset 65
    unsigned char reserved5[10];
};

static struct cfg_t cfg;
int *addr = Display_ID;

static struct i2c_algorithm GM_algorithm = {
	.master_xfer	= iic_xfer,
};

static struct i2c_adapter bit_i2c_adapter = {
	.owner		= THIS_MODULE,
	.id		= I2C_HW_GM,
	.name		= "GM I2C adapter",
	.algo		= &GM_algorithm,
};

int GM_i2c_read(unsigned int i_dev_addr,unsigned int i_dev_offset,unsigned char *buf,unsigned int size,int clockdiv)
{
    int ret , i;
    struct i2c_adapter *adap;
    char *p ;
    struct GMi2c_info *fara_info;
    	    
    p = buf ;
    if(! (fara_info = kmalloc(sizeof(struct GMi2c_info),GFP_KERNEL)))
	return -ENOMEM;
    adap=fara_info;
    
    memcpy(adap,&bit_i2c_adapter,sizeof(struct i2c_adapter));
    I2C_LOCK(adap); 
    fara_info->data = i_dev_offset;		//I2C offset
    fara_info->flags = i_dev_addr;	//I2C device address
    fara_info->client_count = clockdiv;	//use the default system I2C bus clock
    for (i=0 ; i<size ; i++) {
        if (fara_info->client_count >= 0 && fara_info->client_count < 500 ) {
                    ret = GM_fLib_I2C_SetClockdiv(fara_info->client_count);
                    if (ret !=0 ) {
			    printk("i2c-algo-GM.o:Error in SetClockdiv of GM_i2c_write\n");
	                    return ret;
	            }
        }
	ret = i2c_readbytes(adap, p, 1);
    	if (ret != 1){
		printk("i2c-GM-adap.o: GM_i2c_write error(ret:0x%x), data = 0x%x!\n",ret,*p);
    	}
	p++;
    	fara_info->data++ ;	
    }
    I2C_UNLOCK(adap);
    kfree(fara_info);    
    return ret;
}

int GM_i2c_write(unsigned int i_dev_addr,unsigned int i_dev_offset,unsigned char *buf,unsigned int size,int clockdiv)
{
    int ret,i ;
    unsigned char *p;
    struct i2c_adapter *adap;
    struct GMi2c_info *fara_info;
        
    if(! (fara_info = kmalloc(sizeof(struct GMi2c_info),GFP_KERNEL)))
	return -ENOMEM;
    adap=fara_info;
    	
    memcpy(adap,&bit_i2c_adapter,sizeof(struct i2c_adapter));
    I2C_LOCK(adap); 
    fara_info->data = i_dev_offset;		//I2C offset
    fara_info->flags = i_dev_addr;	//I2C device address
    fara_info->client_count = clockdiv;	//use the default system I2C bus clock

    p = buf ;		
    for (i=0 ; i<size ; i++) {
        if (fara_info->client_count >= 0 && fara_info->client_count < 500 ) {
                    ret = GM_fLib_I2C_SetClockdiv(fara_info->client_count);
                    if (ret !=0 ) {
			    printk("i2c-algo-GM.o:Error in SetClockdiv of GM_i2c_write\n");
	                    return ret;
	            }
        }
	ret = i2c_sendbytes(adap, p, 1);
    	if (ret != 1){
		printk("i2c-GM-adap.o: GM_i2c_write error(ret:0x%x), offset:0x%x data = 0x%x!\n",ret,fara_info->data,*p);
    	}
    	fara_info->data++ ;	
	p++;
    }
    I2C_UNLOCK(adap); 
    kfree(fara_info);
    return size;
}

static void seeprom_read(unsigned int start_addr,unsigned int size,unsigned char *buf)
{
    int ret;
    //struct i2c_msg msg ;
    //char *temp;
    struct GMi2c_i2c_client *client;
	
    if(! (client = kmalloc(sizeof(struct GMi2c_i2c_client),GFP_KERNEL)))
	return -ENOMEM;
    memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client));
    client->adapter = &bit_i2c_adapter; 
    
    //client->addr = Display_ID; 
    //for(i=0;i<size;i++,buf++)
    client->adapter->data = start_addr;		//I2C offset
    client->adapter->flags = EEPROM_ID_READ;	//I2C device address
    client->adapter->client_count = 0;	//use the default clockdiv
    client->adapter->adap.retries = 0;
    //bit_i2c_adapter.data = start_addr+i;
    //bit_i2c_adapter.algo->master_xfer(&bit_i2c_adapter,&msg,msg.len);
    ret = i2c_master_recv(client,buf,size);
    if ( ret != size ) {
 	printk("i2c-GM-adap.o:Error seeprom_Read!\n");
    }
    kfree(client);
}

static void seeprom_write(unsigned int start_addr,unsigned int size,unsigned char *buf)
{
    struct GMi2c_i2c_client *client;
    int ret,i ;

⌨️ 快捷键说明

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