编辑文章 - 博客频道 - CSDN.NET

来源:互联网 发布:我要上淘宝 编辑:程序博客网 时间:2024/06/07 06:44

最经在一个项目上用到hi3515芯片的i2c配置成从设备用于接收数据。采用中断阻塞方式。i2c硬件缓存区一次只能缓存8个字节,

超出部分会被硬件自动丢去。

代码如下:

hi_i2c.c文件:

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/fcntl.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/list.h>


#include <linux/seq_file.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/irq.h>


#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
#include <linux/kcom.h>
#include <asm-arm/arch-hi3515v100/gpio.h>
#include <asm-arm/arch-hi3515v100/hardware.h>
#include <asm-arm/arch-hi3515v100/io.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/workqueue.h>

#define SC_PERCTRL1 IO_ADDRESS(0x200F0000+0x0098)
#define SD_PERCTRL1 IO_ADDRESS(0x200F0000+0x0094)


#define HCLK_FREQ (100000000)
#define I2C_CLK (HCLK_FREQ)
#define I2C_RATE (50000)
#define CONTROL_VALUE  0x0023


#define I2C_BASE 0x200D0000
#define I2C_REG_READL(reg,result) \
(result=readl(reg))
#define I2C_REG_WRITEL(reg,data) \
(writel(data,reg))
#define I2C_REG_READW(reg,result) \
(result=readw(reg))
#define I2C_REG_WRITEW(reg,data) \
(writew(data,reg))


#define I2C_CON           IO_ADDRESS(I2C_BASE+0x00) /*I2C control reg*/
#define I2C_TAR           IO_ADDRESS(I2C_BASE+0x04) /*slave chip address reg*/
#define I2C_HCNT                   IO_ADDRESS(I2C_BASE+0x14)
#define I2C_LCNT                   IO_ADDRESS(I2C_BASE+0x18)
#define I2C_HS_HCNT                IO_ADDRESS(I2C_BASE+0x1C)
#define I2C_HS_LCNT                IO_ADDRESS(I2C_BASE+0x20)
#define I2C_INTR_MASK          IO_ADDRESS(I2C_BASE+0x30) /*interrupt mask reg*/
#define I2C_SAR                    IO_ADDRESS(I2C_BASE+0x08)
#define I2C_INTR_STAT          IO_ADDRESS(I2C_BASE+0x2C) /*interrupt status reg*/
#define I2C_ENABLE          IO_ADDRESS(I2C_BASE+0x6C) /*IP enable*/
#define I2C_DATA_CMD          IO_ADDRESS(I2C_BASE+0x10) /*I2C TX FIFO*/
#define I2C_TXFIFO_FLAG           IO_ADDRESS(I2C_BASE+0x74) /*indicate TXFIFO level*/
#define I2C_RXFIFO_FLAG           IO_ADDRESS(I2C_BASE+0x78) /*indicate RXFIFO level*/
#define I2C_STATUS           IO_ADDRESS(I2C_BASE+0x70) /*IP status flag reg*/
#define I2C_COMP_PARAM_1           IO_ADDRESS(I2C_BASE+0xF4) /*IP status flag reg*/
#define I2C_TX_TL                  IO_ADDRESS(I2C_BASE+0x3c)
#define I2C_RX_TL                  IO_ADDRESS(I2C_BASE+0x38)
#define I2C_RAW_INTSTATUS          IO_ADDRESS(I2C_BASE+0x34)


/*clear write interrupt reg */
#define I2C_CLR_INTR           IO_ADDRESS(I2C_BASE+0x40) /*clear combined and individual interrupt*/
#define I2C_CLR_TX_ABRT           IO_ADDRESS(I2C_BASE+0x54) /*clear RT abrt interrupt reg*/
#define I2C_CLR_STOPDET            IO_ADDRESS(I2C_BASE+0x60) /*clear stop_det interrupt reg*/
#define I2C_CLR_ACTIVITY           IO_ADDRESS(I2C_BASE+0x5C) /*clear activity*/
#define I2C_CLR_TX_OVER            IO_ADDRESS(I2C_BASE+0x4C) /*clear tx fifo over interrupt reg*/
#define I2C_CLR_RX_ABRT           IO_ADDRESS(I2C_BASE+0x80) /*clear RX abrt interrupt reg*/


#define TIMECOUNT         0x100
#define RW_RETRY_TIME     5


static DECLARE_WAIT_QUEUE_HEAD(waitq);
static volatile int ev_data = 0;


/*
 * sends a character over I2C bus routine.
 * @param sendvalue: character to send
 * @return value:0--success; -1--error.
 *
 */
static int i2csendbyte(unsigned char sendvalue)
{
    unsigned short data = 0x00FF;
    unsigned short status;
    unsigned short count;
    unsigned long i = 0;


    /*set write CMD*/
    data = sendvalue & data;


    /*check TX fifo status*/ //缓存中数据的个数
    I2C_REG_READW(I2C_TXFIFO_FLAG, status);


    /*check TX fifo status*/
    I2C_REG_READW(I2C_TX_TL, count);
    count&=0xff;


    /*TX FIFO full and wait for a while*/
    while(status >= count)
    {
   udelay(20);
   if(++i>TIMECOUNT)
   {
   /*printk("TIME OUT: i2csendbyte\n");*/
   return -1;
   }
   I2C_REG_READW(I2C_TXFIFO_FLAG, status);
    }


    /*write one byte to TX fifo*/
    I2C_REG_WRITEW(I2C_DATA_CMD,data);
    return 0;
}


/*
 * receives a character from I2C bus routine.
 * @return value:character received
 */
static int i2creceivebyte(unsigned char* data)
{
unsigned char ucvalue;
unsigned short status;
unsigned long i = 0;


/*read Rx FIFO*/
//I2C_REG_WRITEW(I2C_DATA_CMD,0x0100);
I2C_REG_READW(I2C_RXFIFO_FLAG, status); //缓存中数据的个数
/*RX FIFO is  empty and wait for a while*/
while(status == 0)
{
udelay(10);
if(++i>TIMECOUNT)
{
        printk("TIME OUT: i2creceivebyte\n");
return -1;
}
I2C_REG_READW(I2C_RXFIFO_FLAG, status);
}


I2C_REG_READW(I2C_DATA_CMD, ucvalue);
*data = ucvalue;
return 0;
}


static int i2creceivebytes(unsigned char * buff, int buff_size)
{
unsigned char *pbuff;
unsigned short status;
int i;
pbuff = buff;
for(i = 0; i < 11; i++)
{
status &= 0;
I2C_REG_READW(I2C_RAW_INTSTATUS, status);
printk("I2C_RAW_INTSTATUS = %#x \n", status);


status &= 0;
I2C_REG_READW(I2C_INTR_STAT, status);
printk("I2C_INTR_STATUS = %#x \n", status);


i2creceivebyte(pbuff);
pbuff++;
}
return 0;
}


static int i2c_receive_bytes(unsigned char * buff, int buff_size)
{
unsigned char status;
unsigned char *pbuff = buff;
int i = 0;
int j;


I2C_REG_READW(I2C_RXFIFO_FLAG, status); //缓存中数据的个数
j = status;
while(j--)
{
I2C_REG_READW(I2C_DATA_CMD, *pbuff);
pbuff++;
// I2C_REG_READW(I2C_RXFIFO_FLAG, status);
}
return 0;
}


/*
 *  read continuing data from the I2C bus of a device rountine.
 *  @param  devaddress:  address of the device
 *  @param  regaddress: address of register within device
 * @param reg_addr_count : regaddress byte count
 *  @param  data:   data point from the device readed
 *  @param  count:  data count from the device readed 
 *  @return value: 0--success; -1--error.
 */
int  hi_i2c_muti_read(unsigned char* data)
{
unsigned long j = 0;
int ret = 0;
int count = 20;
for(j = 0; j < count; j++)
{
ret = i2creceivebyte(data);
if(-1 == ret)
{
return -1;
}
data ++;
}


return 0;
}


static irqreturn_t iic_interrupt(int irq, void * dev_id)
{
unsigned short status;
disable_irq(INTNR_I2C);
I2C_REG_READW(I2C_CLR_ACTIVITY, status);
I2C_REG_READW(I2C_RX_TL, status);
if(status)
{
   ev_data = 1;
   wake_up_interruptible(&waitq);
}
enable_irq(INTNR_I2C);
return IRQ_HANDLED;
}


static int i2c_read(struct file* file, char __user * userbuf, size_t count,loff_t * off)
{
unsigned char buff[100];
int i;


if(!ev_data)
{
if(file->f_flags & O_NONBLOCK)
return -EAGAIN;
else
{
wait_event_interruptible(waitq, ev_data);
}
}
ev_data = 0;


memset(buff, 0, sizeof(buff));
i2c_receive_bytes(buff, sizeof(buff)-2);
// hi_i2c_muti_read(buff);
// i2creceivebytes(buff, sizeof(buff)-2);
if (copy_to_user(userbuf, buff, strlen(buff))!= 0)
{
printk("read is error!!\n");
return EFAULT;
}
return strlen(buff);
}


static int i2c_open(struct inode* inode, struct file* filp)
{
unsigned int cnt, hcnt, lcnt;
unsigned short status;
int i = 0;
unsigned int reg;


/* 配置复用端口    */
I2C_REG_READL(SC_PERCTRL1,reg);
reg &= ~0x00000001;
I2C_REG_WRITEL(SC_PERCTRL1,reg);


I2C_REG_READL(SD_PERCTRL1,reg);
reg &= ~0x00000001;
I2C_REG_WRITEL(SD_PERCTRL1,reg);


I2C_REG_READW(I2C_STATUS, status);
status &= 0x01;
/*I2C BUS is not idle and wait for a while*/
while((status != 0) )
{
udelay(20);
if(++i>TIMECOUNT)
{
printk("i2c TimeCount \n");
break;
}
I2C_REG_READW(I2C_STATUS, status);  
status &= 0x01;



I2C_REG_WRITEW(I2C_ENABLE, 0);  //禁止i2c
/* standard speed.*/
cnt = I2C_CLK/I2C_RATE;
hcnt = (cnt/9)*4;
lcnt = (cnt/9)*5;


I2C_REG_WRITEW(I2C_CON, 0x0002);//关闭重新发送起始位,配置从端模式等

I2C_REG_WRITEW(I2C_SAR, 0x07F); //设置作为从机i2c地址

I2C_REG_WRITEW(I2C_RX_TL, 0x00ff);
I2C_REG_WRITEW(I2C_TX_TL, 0x00ff);

I2C_REG_WRITEW(I2C_INTR_MASK, 0x0100); //开启中断


I2C_REG_WRITEW(I2C_ENABLE, 1);


return 0;
}


static int i2c_release(struct inode* inode, struct file* filp)
{
return 0;
}


static int i2c_ioctl(struct inode* inode, struct file* filp,unsigned int cmd, unsigned long arg)
{
return 0;
}


static struct file_operations i2c_fops = {
owner:THIS_MODULE,
      open:i2c_open,
      read:i2c_read,
      ioctl:i2c_ioctl,
      release:i2c_release,
};


static struct miscdevice i2c_dev = {
MISC_DYNAMIC_MINOR,
"i2c",
&i2c_fops,
};


static int __init hi_i2c_init(void)
{
int ret;


ret = misc_register(&i2c_dev); //注册字符设备
if (ret)
{
printk(KERN_ERR "register misc dev for i2c fail!\n");
return ret;
}

ret = request_irq(INTNR_I2C, iic_interrupt, IRQF_SHARED, "i2c", iic_interrupt); //申请中断
if (ret < 0)
{
printk("the iic_interrupt is requestted fail\n");
return ENODEV;
} else {
printk("the iic_interrupt is requestted sccuss!! \n");
}

return 0;


}


static void __exit hi_i2c_exit(void)
{
misc_deregister(&i2c_dev);
disable_irq(INTNR_I2C);
free_irq(INTNR_I2C, iic_interrupt);
}

module_init(hi_i2c_init);
module_exit(hi_i2c_exit);


#ifdef MODULE
#include <linux/compile.h>
#endif
MODULE_INFO(build, UTS_VERSION);
MODULE_LICENSE("GPL");
MODULE_VERSION("HI_VERSION=" OSDRV_MODULE_VERSION_STRING);

仅供参考,如有理解错误,或不对的地方欢迎指出。。微笑微笑微笑微笑微笑微笑微笑微笑微笑微笑

0 0
原创粉丝点击