📄 i2c-gm-adap.c
字号:
#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 + -