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

📄 ov_sensor.c

📁 onmivision 摄相头模块驱动程序,blackfin 平台参考设计.
💻 C
字号:
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <asm/bug.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/slab.h>

#include "ov_sensor.h"


//#define OV_DBG		1


#define malloc(x) kmalloc(x, GFP_KERNEL)
#define free(x)   kfree(x)
#define printf(format, arg...)  printk( format, ## arg)
#define assert_(x) BUG_ON(!(x))

#include <asm/irq.h>
#include <asm/blackfin.h>
#include <asm/dma.h>
#include <asm/cacheflush.h>
#include <asm-blackfin/mach-bf533/irq.h>
#define VIDEO_BUF_NUM		10
#define	COL_NUM			320	
#define ROW_NUM			240
#define PPI_DMA_IOBASE		DMA0_NEXT_DESC_PTR
		
#define SSYNC __builtin_bfin_ssync()

	
#define	I2C_CYCLE		0
#define SENSOR_CYCLE		1

static unsigned char ID_addr = 0x00;
static int current_cmd = SENSOR_CYCLE;
static unsigned char current_i2c_addr;
static long current_arg;

static dmasg_t VideoDmaPtr[VIDEO_BUF_NUM];
static char VideoDmaBuf[VIDEO_BUF_NUM][COL_NUM][ROW_NUM];
static dma_register_t* DmaRegPhy = (dma_register_t*)PPI_DMA_IOBASE;



#define HHBF_I2C_SCLK               (1 << 11)
#define HHBF_I2C_SDATA              (1 << 10)

#define I2C_HW_B_HHBF               I2C_HW_B_FRODO  /* 0x13 */

static void hhbf_setsda(int state)
{
#if 0   /* comment by mhfan */
    if (state)
        *pFIO_FLAG_D |=  HHBF_I2C_SDATA;
    else
        *pFIO_FLAG_D &= ~HHBF_I2C_SDATA;
#else

    if (state) {
        *pFIO_DIR    |=  HHBF_I2C_SDATA;
        SSYNC;
        *pFIO_INEN   &=  ~HHBF_I2C_SDATA;   //
        SSYNC;
        *pFIO_FLAG_D |=  HHBF_I2C_SDATA;
        SSYNC;

    } else {
        //*pFIO_INEN   &= ~HHBF_I2C_SDATA;   //
        //SSYNC;

        *pFIO_DIR    |=  HHBF_I2C_SDATA;
        SSYNC;
        *pFIO_INEN   &=  ~HHBF_I2C_SDATA;   //
        SSYNC;
        *pFIO_FLAG_D &= ~HHBF_I2C_SDATA;
        SSYNC;

  	}
udelay(80);
#endif  /* comment by mhfan */
}

static void hhbf_setscl(int state)
{
    if (state)
        {
        *pFIO_FLAG_D |=  HHBF_I2C_SCLK;
        SSYNC;
        }
    else
        {
        *pFIO_FLAG_D &= ~HHBF_I2C_SCLK;
        SSYNC;
        }
udelay(80);
 }

static int hhbf_getsda(void)
{

	unsigned int data_tmp;
        *pFIO_DIR       &=  ~HHBF_I2C_SDATA;
        SSYNC;
        *pFIO_INEN      |=   HHBF_I2C_SDATA;
        SSYNC;
	data_tmp = *pFIO_FLAG_D & HHBF_I2C_SDATA;
	udelay(80);
    return (data_tmp);
}

void i2c_hhbf_init(void)
{
    *pFIO_DIR      |=  HHBF_I2C_SCLK;           // Set SCLK as output
        SSYNC;
    *pFIO_POLAR    &= ~HHBF_I2C_SDATA;          // Enable Active Hight
        SSYNC;
    *pFIO_EDGE     &= ~HHBF_I2C_SDATA;          // Enable Level Sensitivity
        SSYNC;
    *pFIO_INEN     |=  HHBF_I2C_SDATA;          // Enable SDATA Input Buffer
        SSYNC;
    *pFIO_DIR      &= ~HHBF_I2C_SDATA;  // Set SDATA as input/high
        SSYNC;
#if 0   /* comment by mhfan */
    *pFIO_DIR      |=  HHBF_I2C_SDATA;
    *pFIO_FLAG_D   |=  HHBF_I2C_SDATA;
#endif  /* comment by mhfan */
    *pFIO_FLAG_D   |=  HHBF_I2C_SCLK;           // Set SCLK high
        SSYNC;
    
}

unsigned char hhbf_read(unsigned char addr)
{
	char i;
	unsigned char data_tmp=0;
	unsigned char data_pattern[] = {0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80};

#ifdef OV_DBG
        printk("current i2c op is read\n");
	printk("current ID addr is %x\n",ID_addr);
	printk("cureent read addr is %x\n",addr);
#endif
        /*start bit */
        hhbf_setscl(1);
        hhbf_setsda(1);
	hhbf_setsda(0);
	hhbf_setscl(0);
                
	/* setting ID address*/
	for(i = 6;i >= 0;-- i)
		{
		hhbf_setscl(0);
		if (ID_addr & data_pattern[i])
			hhbf_setsda(1);
		else
			hhbf_setsda(0);
		hhbf_setscl(1);
		}
	hhbf_setscl(0);
	
	/*This is a write op */
	hhbf_setsda(0);  
	hhbf_setscl(1);
	hhbf_setscl(0);

	/* settting the x bit */
	hhbf_getsda();
	hhbf_setscl(1);
	hhbf_setscl(0);

	/* setting sub-address */
	for(i = 7;i >= 0;--i)
		{
		hhbf_setscl(0);
		if (addr & data_pattern[i])
			hhbf_setsda(1);
		else
			hhbf_setsda(0);
		hhbf_setscl(1);
		}
	hhbf_setscl(0);

	/* settting the x bit */
	hhbf_getsda();
        hhbf_setscl(1);
        hhbf_setscl(0);


	/*stop bit */
        hhbf_setscl(0);
        hhbf_setsda(0);
        hhbf_setscl(1);
        hhbf_setsda(1);	



        /*start bit */
        hhbf_setscl(1);
        hhbf_setsda(1);
        hhbf_setsda(0);
        hhbf_setscl(0);

        /* setting ID address*/
        for(i = 6;i >= 0;--i)
                {
                hhbf_setscl(0);
                if (ID_addr & data_pattern[i])
                        hhbf_setsda(1);
                else
                        hhbf_setsda(0);
                hhbf_setscl(1);
                }
        hhbf_setscl(0);

        /*This is a read op */
        hhbf_setsda(1);
        hhbf_setscl(1);
        hhbf_setscl(0);

        /* settting the x bit */
        hhbf_getsda();
        hhbf_setscl(1);
        hhbf_setscl(0);

	data_tmp = 0;
	for (i = 7;i >= 0;--i)
		{
		hhbf_setscl(0);
		hhbf_setscl(1);
		if (hhbf_getsda())
			data_tmp |= data_pattern[i];
		}
	hhbf_setscl(0);
	
	/*stop bit */
        hhbf_setscl(0);
        hhbf_setsda(0);
        hhbf_setscl(1);
        hhbf_setsda(1);
	
	return data_tmp;
}

void hhbf_write(unsigned char addr,unsigned char data)
{
        char i;
        unsigned char data_pattern[] = {0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80};

#ifdef OV_DBG
        printk("current i2c op is  write\n");
	printk("current ID addr is %x\n",ID_addr);
	printk("current write addr is %x\n",addr);
	printk("current write data is %x\n",data);
#endif
        /*start bit */
        hhbf_setscl(1);
        hhbf_setsda(1);
        hhbf_setsda(0);
        hhbf_setscl(0);

        /* setting ID address*/
        for(i = 6;i >= 0;--i)
                {
                hhbf_setscl(0);

                if (ID_addr & data_pattern[i])
                        hhbf_setsda(1);
                else
                        hhbf_setsda(0);
                hhbf_setscl(1);
                }
        hhbf_setscl(0);
	
	/*This is a write op */
        hhbf_setsda(0);
        hhbf_setscl(1);
        hhbf_setscl(0);

        /* settting the x bit */
        hhbf_getsda();
        hhbf_setscl(1);
        hhbf_setscl(0);

        /* setting sub-address */
        for(i = 7;i >= 0;--i)
                {
                hhbf_setscl(0);
                if (addr & data_pattern[i])
                        hhbf_setsda(1);
                else
                        hhbf_setsda(0);
                hhbf_setscl(1);
                }
        hhbf_setscl(0);

        /* settting the x bit */
        hhbf_getsda();
        hhbf_setscl(1);
        hhbf_setscl(0);

        for (i = 7;i >= 0;--i)
                {
                hhbf_setscl(0);
                if (data & data_pattern[i])
			hhbf_setsda(1);
		else
			hhbf_setsda(0);
		hhbf_setscl(1);
                }
        hhbf_setscl(0);

	/* settting the x bit */
        hhbf_getsda();
    	hhbf_setscl(1);
        hhbf_setscl(0);

        /*stop bit */
        hhbf_setscl(0);
        hhbf_setsda(0);
        hhbf_setscl(1);
        hhbf_setsda(1);
}

static void setup_desc(dmasg_t* desc, void* buf,unsigned int cfg, unsigned int x_count, unsigned int ycount){

  int i;

  for( i=0; i < VIDEO_BUF_NUM; ++i ){
    desc[i].next_desc_addr  = (unsigned long)&( desc[i + 1] );
    desc[i].start_addr = (unsigned long)buf + i * COL_NUM * ROW_NUM;
    desc[i].cfg = cfg;
    desc[i].x_count = x_count;
    desc[i].x_modify = sizeof(long);
    desc[i].y_count = ycount;
    desc[i].y_modify = sizeof(long);
  }

  desc[VIDEO_BUF_NUM - 1].next_desc_addr = (unsigned long)desc; /* make circular */

/*  printk(KERN_ERR"setup desc: desc0=%p, next0=%lx, desc1=%p, next1=%lx\nx_count=%x,y_count=%x,addr=0x%lx,cfs=0x%x\n", 
  	&(desc[0]), desc[0].next_desc_addr, 
	&(desc[1]), desc[1].next_desc_addr,
	desc[0].x_count, desc[0].y_count, desc[0].start_addr,desc[0].cfg);
 */

  flush_dcache_range((unsigned int)desc, (unsigned int)desc + VIDEO_BUF_NUM * sizeof(dmasg_t));
}

static struct proc_dir_entry *rtc_ent;
static int pid_process = 0;
static int sig_count = 0;

static unsigned int glab_count = 0; 

static loff_t ov_llseek(struct file *file, loff_t offset, int origin);
static ssize_t ov_read(struct file *file, char *buf,size_t count, loff_t *ppos);
static ssize_t ov_write(struct file *file,const char *buf,size_t count,loff_t *ppos);
static int ov_ioctl(struct inode *inode, struct file *file, unsigned int cmd,unsigned long arg);
static int ov_open(struct inode *inode, struct file *file);
static int ov_release(struct inode *inode, struct file *file);


#if 0
   static read_proc_t* pid_rcv_read_proc(char *page, char **start, off_t off, int count,int *eof, void *data)
    	{
    	int len;
    	len = sprintf(page, "%d\n", pid_process);
	len -= off;
	*start = page + off;

	if (len > count)
		len = count;
	else
		*eof = 1;

	if (len < 0)
		len = 0;
     //printk("curren imask equal %x\n",*pSIC_IMASK);
	return len;
    	}
  

    static write_proc_t* pid_rcv_write_proc(struct file *file, const char __user *buffer,unsigned long count, void *data)
    	{
    		char  temp[10];
		int i = 1;
		int j = 0;
		int data_tmp = 0;
		for (j=0;j<count -2;j++)
			i = 10 * i;
		//printk("currnet i equal : %d\n",i);
		copy_from_user(temp,buffer,count);
		j=0;
		for (;i>0;i=i/10){
			//printk("current char equal: %c\n",temp[j]);
		data_tmp = data_tmp+ (temp[j] - 48)*i;
			//printk("current data_tmp : %d\n",data_tmp);
		j++;
			}
		pid_process = data_tmp;
		//printk("pid_process equal : %d\n",data_tmp);
		//printk("string 	is  equal : %s\n",temp);
    	    	return count;
    	}

#endif

static struct file_operations ov_fops = {
    owner:      THIS_MODULE,
    llseek:       ov_llseek,
    read:         ov_read,
    write:	  ov_write,
    ioctl:        ov_ioctl,
    open:         ov_open,
    release:      ov_release
    };

static struct miscdevice ov_dev =
{
    OV_SENSOR_MINOR,
    "ov_sensor",
    &ov_fops
};



static loff_t ov_llseek(struct file *file, loff_t offset, int origin)
{
return 0;
}

static ssize_t ov_read(struct file *file, char *buf,size_t count, loff_t *ppos)
{ 

if (current_cmd == I2C_CYCLE)
	
	return (hhbf_read(current_i2c_addr));	
else
	return 0;
}

static ssize_t ov_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
{
if (current_cmd == I2C_CYCLE)
	{
	//printk("current_i2c_addr is %x  buf data is %x\n",current_i2c_addr,buf[0]); 
	hhbf_write(current_i2c_addr,buf[0]);
	}
return 0;
}

static int ov_ioctl(struct inode *inode, struct file *file, unsigned int cmd,unsigned long arg)
{
	current_cmd = cmd;
	if (cmd == I2C_CYCLE)
		{
		current_i2c_addr = (unsigned char) arg;
		ID_addr		 = (unsigned char)(arg >> 8);
		}
return 0;
}

static int ov_open(struct inode *inode, struct file *file)
{
*pPPI_CONTROL = 0xc1;
SSYNC;

return 0;
}

static int ov_release(struct inode *inode, struct file *file)
{
*pPPI_CONTROL = 0xc0;
SSYNC;

return 0;

}

static irqreturn_t ppi_error_handler(int irq, void *dev_id, struct pt_regs *regs){
#ifdef OV_DBG
	printk("in module ppi_error_handler\n");
#endif
	*pDMA0_IRQ_STATUS |= (DMA_DONE | DMA_ERR);
	SSYNC;
#ifdef OV_DBG  
	printk("*pPPI_STATUS = %x\n",*pPPI_STATUS); /* read it to clear the error */	
#else
	*pPPI_STATUS = *pPPI_STATUS;
	SSYNC;
#endif  	
	return IRQ_HANDLED;
}
static irqreturn_t ppi_rx_handler(int irq, void *dev_id, struct pt_regs *regs){
#ifdef OV_DBG
	printk("in module ppi_rx_handler\n" ); 
#endif  
	*pDMA0_IRQ_STATUS |= (DMA_DONE | DMA_ERR);
	SSYNC;
	return IRQ_HANDLED;
}

static void __exit ov_exit(void){
   	deregister(&ov_dev);
	return 0;
}
static int __init ov_init(void){

static int id3;
#if 0
#define pPPI_CONTROL 
#define pPPI_STATUS
#define pPPI_DELAY 
#define pPPI_COUNT
#define pPPI_FRAME 

*pPPI_CONTROL = 0x40c; 
SSYNC;

setup_desc(VideoDmaPtr,VideoDmaBuf,0x7817, COL_NUM, ROW_NUM);
*pDMA0_CONFIG =  0x7816;
*pDMA0_NEXT_DESC_PTR = VideoDmaPtr; 
SSYNC;
#ifdef OV_DBG
	printk("start request dma sources!%d,%d,%x,%x\n",IRQ_PPI,IRQ_PPI_ERROR,&VideoDmaPtr[1],&VideoDmaBuf[1]);
#endif

if(request_dma(0,"PPI RX Data") == -EBUSY){
     printk("Unable to allocate PPI RX dma %d\n", IRQ_PPI);
     return NULL ;
  }
if( set_dma_callback(0,ppi_rx_handler, NULL) != 0){
    printk("Unable to set PPI RX dma handler%d\n", IRQ_PPI);
    free_dma(IRQ_PPI);
    return NULL ;
  }  
#ifdef OV_DBG
	printk("start request ppi error sources!\n");
#endif
if( request_irq(IRQ_PPI_ERROR, &ppi_error_handler, SA_SHIRQ, "PPI RX ERROR", &id3) ){
    printk( "Unable to allocate ppi error  IRQ %d\n", IRQ_TMR0);
    ov_exit();
    return -ENODEV;
  }

enable_irq(IRQ_PPI_ERROR);

#ifdef OV_DBG
	printk("I am ov_sensor init!%x\n",*((volatile unsigned long*) 0xffe02104));
#endif
enable_dma(0);

*pDMA0_CONFIG = 0x7817;
SSYNC;


//*pPPI_CONTROL = 0x40cd;
//SSYNC;

printk("pDMA0_CONFIG: = %x\n",*pDMA0_CONFIG);
printk("pPPI_STATUS: = %x\n",*pPPI_STATUS);

#endif
misc_register(&ov_dev);
i2c_hhbf_init();
return 0;
}
  
MODULE_AUTHOR("maji<maji_999@163.com>");
MODULE_DESCRIPTION("ov_sensor");
MODULE_LICENSE("GPL");



module_init(ov_init);
module_exit(ov_exit);




⌨️ 快捷键说明

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