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

📄 iic.c

📁 s3c2410
💻 C
字号:

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/poll.h>
#include <linux/wait.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <asm/arch/irqs.h>

#include <linux/input.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <asm/signal.h>
#include <asm/hardware.h>
#include <asm/uaccess.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-irq.h>
#include <asm/dma.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/ctype.h>
#include <linux/pagemap.h>

#include <linux/config.h>
#include <linux/miscdevice.h>
#include <linux/spinlock.h>
#include <linux/device.h>
#include <linux/devfs_fs_kernel.h>
#include <asm/arch/regs-mem.h>
#include <asm/arch/regs-iic.h>
#include <asm/arch/map.h>





#define WRDATA         (1)
#define POLLACK        (2)
#define RDDATA         (3)
#define SETRDADDR      (4)

#define IICBUFSIZE 0x20

MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS("IIC_ZLG7290");
MODULE_AUTHOR("panwsecjtu@yhoo.com.cn");
MODULE_DESCRIPTION("Study");
MODULE_SUPPORTED_DEVICE(DEVICE);


//ZLG7290 SlaveAddress
#define ZLG7290_SlaveADDR 0x70       //IIC从设备地址

//ZLG7290 Register
#define ZLG7290_SystemReg  0x00  	 //系统寄存器
#define ZLG7290_Key   0x01           //获取键值寄存器地址,复位为00H		 
#define ZLG7290_RepeatCnt  0x02      //按键重复按的次数	




#define DEVICE          "IIC_ZLG7290"
#define BIT_IIC        (0x1<<27)

int major = 233;
int minor = 0;
void *R_GPECON,*R_GPEUP,*R_GPFCON,*R_GPFUP,*R_EXTINT0,*R_IICCON,*R_IICSTAT,*R_IICADD,*R_IICDS;


#define U8 unsigned char
#define U32 unsigned int
static unsigned char _iicData[IICBUFSIZE];
static volatile int _iicDataCount;
static volatile int _iicStatus;
static volatile int _iicMode;
static int _iicPt;
static int flag = 0;
struct work_struct Iic_wq; //工作队列

void Iic_do_work(void);
void _Rd2410Iic(U32 slvAddr,U32 addr,U32 *rdata);
void Run_IicPoll(void);
void IicPoll(void);
static U8  Getkey_zlg7290(void);



int IIC_open(struct inode *, struct file *);
int IIC_release(struct inode *, struct file *);
ssize_t IIC_read(struct file *file, char* buf, size_t count, loff_t *f_pos);
unsigned int IIC_poll(struct file* file, poll_table* wait);
irqreturn_t interrupt_handle( int irq, void* dev_id, struct pt_regs* regs );



static struct file_operations fops = {
        .owner = THIS_MODULE,
        .read = IIC_read,
        .open = IIC_open,
        .release = IIC_release,
        .poll =  IIC_poll,
};


static void address_map(void)
{
#define  GPIO_BASE      (0x56000000)
#define  IIC_GPECON     ( GPIO_BASE + 0x40 )
#define  IIC_GPEUP      ( GPIO_BASE + 0x48 )
#define  IIC_GPFCON     ( GPIO_BASE + 0x50 )
#define  IIC_GPFUP      ( GPIO_BASE + 0x58 )
#define  IIC_EXTINT0    ( GPIO_BASE + 0x88 )
#define  IIC_BASE       (0x54000000)
#define  IIC_CON        ( IIC_BASE + 0x0 )
#define  IIC_STAT       ( IIC_BASE + 0x4 )
#define  IIC_ADDR       ( IIC_BASE + 0x8 )
#define  IIC_DS         ( IIC_BASE + 0xC )
        R_GPECON  = ioremap(IIC_GPECON,4);
        R_GPEUP   = ioremap(IIC_GPEUP ,4);
		R_GPFCON  = ioremap(IIC_GPFCON,4);
        R_GPFUP   = ioremap(IIC_GPFUP ,4);
		R_EXTINT0 = ioremap(IIC_EXTINT0 ,4);
        R_IICCON  = ioremap(IIC_CON   ,4);
        R_IICSTAT = ioremap(IIC_STAT  ,4);
        R_IICADD  = ioremap(IIC_ADDR  ,4);
        R_IICDS   = ioremap(IIC_DS    ,4);
}

static void address_unmap(void)
{
        iounmap( R_GPECON );
        iounmap( R_GPEUP );
		iounmap( R_GPFCON );
        iounmap( R_GPFUP );
        iounmap( R_EXTINT0 );
        iounmap( R_IICCON );
        iounmap( R_IICSTAT );
        iounmap( R_IICADD );
        iounmap( R_IICDS );
}



struct IIC_dev{
        wait_queue_head_t rq;   // 读取等待队列
        uint8_t key;            //用于存放键值
        struct semaphore sem;  
        struct cdev cdev;
};
struct IIC_dev *zlg7290_dev;


//*********************[ Delay ]*********************************
void Delay(int times)
{
	udelay(1000);
}


		
//************************[ _Rd2410Iic ]*******************************
void _Rd2410Iic(U32 slvAddr,U32 addr,U32 *rdata)
{
   	printk("read---->0\n");
    _iicMode      = SETRDADDR;
    _iicPt        = 0;
    _iicData[0]   = (U8)addr;
    _iicDataCount = 1;
    writeb(  slvAddr&0xfe,  R_IICDS );
    writeb(  0xf0,  R_IICSTAT  );

   // R_IICDS   = slvAddr&0xfe;            //写入从机的地址
   // R_IICSTAT = 0xf0;                    //MasTx,Start  主机发送数据开始

    //Clearing the pending bit isn't needed because the pending bit has been cleared.
    while(_iicDataCount!=-1)
        Run_IicPoll();
	
    _iicMode      = RDDATA;
    _iicPt        = 0;
    _iicDataCount = 1;
    
   // R_IICDS   = slvAddr|0x01;        //读zlg7290键值寄存器 ,地址是:0x01
   // R_IICSTAT = 0xb0;                //Master Rx,Start
   // R_IICCON  = 0xaf;                //Resumes IIC operation.   
   writeb( slvAddr|0x01,  R_IICDS  );
   writeb( 0xb0, R_IICSTAT   );
   writeb( 0xaf, R_IICCON   );

    while(_iicDataCount!=-1)
        Run_IicPoll();

    *rdata = _iicData[1];
   
	
}

//**********************[ Run_IicPoll ]*********************************
void Run_IicPoll(void)
{
  U8 tmp;
 
  tmp = __raw_readb(R_IICCON);
  tmp=tmp&0x10;
  if(tmp)              
   IicPoll();
   
   // if(R_IICCON & 0x10) 
   
}       


    
//**********************[IicPoll ]**************************************
void IicPoll(void)
{
    U32 iicSt,i;
    iicSt= __raw_readb(R_IICSTAT);
 // iicSt = R_IICSTAT; 
    if(iicSt & 0x8){
	printk("bus arbitration is failed\n");
			}   //When bus arbitration is failed.
    if(iicSt & 0x4){
	printk("matched\n");
	}                   //When a slave address is matched with IICADD
    if(iicSt & 0x2){
	printk("slave address 0000000b\n");
	}                   //When a slave address is 0000000b
    if(iicSt & 0x1){
	printk("Ack isn't received\n");
	}                   //When ACK isn't received

    switch(_iicMode)
    {
        case POLLACK:
		printk("poll--ACK\n");
            _iicStatus = iicSt;
            break;

        case RDDATA:
              printk("read--ACK\n");
            if((_iicDataCount--)==0)
            {
                //_iicData[_iicPt++] = R_IICDS;
              _iicData[_iicPt++] = __raw_readb(R_IICDS);
               // R_IICSTAT = 0x90;             //Stop MasRx condition 
               // R_IICCON  = 0xaf;             //Resumes IIC operation.
                 writeb(0x90,R_IICSTAT);
                 writeb(0xaf,R_IICCON);

                Delay(1);              //Wait until stop condtion is in effect.
                                                //Too long time... 
          //The pending bit will not be set after issuing stop condition.
                break;    
            }      
           // _iicData[_iicPt++] = R_IICDS;
            _iicData[_iicPt++] = __raw_readb(R_IICDS);

                        //The last data has to be read with no ack.
            if((_iicDataCount)==0)
               // R_IICCON = 0x2f;     //Resumes IIC operation with NOACK.
               writeb(0x2f,R_IICCON);  
            else 
               // R_IICCON = 0xaf;     //Resumes IIC operation with ACK
                writeb(0xaf,R_IICCON);
            break;

        case SETRDADDR:
		printk("SETRDADDR\n");
            if((_iicDataCount--)==0)
            {
                break;        //IIC operation is stopped because of IICCON[4]    
            }
           // R_IICDS = _iicData[_iicPt++];
             writeb(_iicData[_iicPt++],R_IICDS);
            for(i=0;i<10;i++);     //for setup time until rising edge of IICSCL
           // R_IICCON = 0xaf;             //resumes IIC operation.
             writeb(0xaf,R_IICCON);

            break;

        default:
            break;      
    }
}



static U8  Getkey_zlg7290(void)
{
	U8 keypress;
      //  U8 repeatcount;

	static U32 rdata;
	_Rd2410Iic(ZLG7290_SlaveADDR, ZLG7290_Key,&(rdata));//第254行,第二个错误在这里
//	repeatcount=_Rd2410Iic(ZLG7290_SlaveADDR, ZLG7290_RepeatCnt,&(rdata));//这个没有用到
        keypress=rdata;
    return keypress;
}


static int __init IIC_init(void)
{       U8 tmp1;
        int ret;
        U32 tmp; 
        // 1.
        dev_t devno = MKDEV( major, minor );
        ret = register_chrdev_region( devno, 1, DEVICE );
        if( ret < 0 )
        {
          printk(KERN_DEBUG "register major number failed with %d\n", ret);
          return ret;
        }
        printk(KERN_DEBUG "%s:register major number OK\n",DEVICE);

        // 2.
        zlg7290_dev = kmalloc(sizeof(struct IIC_dev), GFP_KERNEL);
        memset( zlg7290_dev, 0, sizeof(struct IIC_dev) );
        cdev_init( &zlg7290_dev->cdev, &fops );
        zlg7290_dev->cdev.ops = &fops;
        zlg7290_dev->cdev.owner = THIS_MODULE;
        ret = cdev_add( &zlg7290_dev->cdev, devno, 1 );
        if( ret < 0 )
        {
          printk(KERN_DEBUG "register device failed with %d\n", ret);
          return ret;
        }
        printk(KERN_DEBUG "%s:register device OK\n",DEVICE);

        // 3.
        init_MUTEX( &(zlg7290_dev->sem) );
        printk(KERN_DEBUG "%s:init semaphore OK\n",DEVICE);

        // 4. 初始化等待队列头
        init_waitqueue_head(&zlg7290_dev->rq);

        // 5. Remap IIc
        address_map();
       
	//7
        tmp = readl( R_GPFCON );
        tmp |= 0x00000020;     
        writel( tmp, R_GPECON );
		
	tmp = readl( R_GPFUP );
        tmp |= 0x04;          //Pull-up disable
        writel( tmp, R_GPFUP );
        tmp = readl( R_EXTINT0 );
        tmp &= 0x0;          //设置EINT2为低电平触发
        writel( tmp, R_GPFUP );
	// 8. 初始化底半部中断工作队列
	INIT_WORK(&Iic_wq,(void(*)(void*))Iic_do_work,NULL);
		
	// 9. 设置 R IIC
        tmp = readl( R_GPEUP );
        tmp |= 0xc000;          //Pull-up disable
        writel( tmp, R_GPEUP );

        tmp = readl( R_GPECON );
        tmp |= 0xa0000000;      //GPE15:IICSDA , GPE14:IICSCL
        writel( tmp, R_GPECON );
	//R_IICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);
        //R_IICSTAT = 0X10;
        tmp1= ((1<<7)|(0<<6)|(1<<5)|(0xf));
        writeb(tmp1,R_IICCON );
        writeb(0x10,R_IICSTAT);
     
    	return 0;
}


static void __exit IIC_exit(void)
{
        dev_t devno = MKDEV( major, minor );
        address_unmap();
        cdev_del( &zlg7290_dev->cdev );
        kfree( zlg7290_dev );
        printk(KERN_DEBUG "%s:kfree OK\n",DEVICE);
        unregister_chrdev_region( devno, 1 );
        printk(KERN_DEBUG "%s:unregister device OK\n",DEVICE);
}

int IIC_open(struct inode *inode, struct file *file)
{
        int ret;
    
        struct IIC_dev *dev = container_of(inode->i_cdev, struct IIC_dev, cdev);
        file->private_data = dev;

        if( down_interruptible(&dev->sem) )
                return -ERESTARTSYS;

//        set_slave_recv_mode();

         ret = request_irq( IRQ_EINT2, interrupt_handle,
                                    SA_INTERRUPT, DEVICE, (void*)dev );
        if( ret )
        {
                printk( KERN_INFO "I2C: can't get assigned irq %d\n", IRQ_IIC );
        }
   


        return 0;
}



int IIC_read(struct file *file, char* buf, size_t count, loff_t *f_pos)
{
        struct IIC_dev *dev = file->private_data;
			int sum=0;
			if(flag==1)
			{
				flag = 0;
				sum=1;
				if (copy_to_user(buf,&dev->key,1))
				{
					sum=-EFAULT; 
				}
			}
			else
			{
				if (file->f_flags & O_NONBLOCK)
				{
					return -EAGAIN;
				}
				else
				{
					if(wait_event_interruptible(dev->rq, flag != 0))                      		                 {
						return - ERESTARTSYS;
					}	
					flag = 0;
					sum=1;
					if (copy_to_user(buf,&dev->key,1))
					{
						sum=-EFAULT; 
					}	
				}
			}
			dev->key = 0;
			return sum;
}

int IIC_release(struct inode *inode, struct file *file)
{
        struct IIC_dev *dev = file->private_data;

        writeb( 0x0, R_IICCON );
        writeb( 0x0, R_IICADD );
        writeb( 0x0, R_IICSTAT);
        barrier(); 
	free_irq( IRQ_EINT2, interrupt_handle );
        printk( KERN_INFO "free IRQ_EINT2 INTerrupt\n" );

	up(&dev->sem);
        return 0;
}

unsigned int IIC_poll(struct file* file, poll_table* wait)
{
        struct IIC_dev *dev = file->private_data;
		unsigned int mask = 0;
		poll_wait(file, &dev->rq, wait);
		if (flag==1)//数据准备好
		{
			mask |= POLLIN | POLLRDNORM; //设备可无阻塞的读
		}
		return  mask;
}

void Iic_do_work(void) 
{
		int code = -1 ;
		code = Getkey_zlg7290();
		enable_irq(IRQ_EINT2);//使能中断
		if(code>0)
		{
			zlg7290_dev->key=code;
 	       	printk("get key %d\n",zlg7290_dev->key);
			flag = 1;
			wake_up_interruptible(&(zlg7290_dev->rq));
		}

}

//**************顶半部中断***********************
irqreturn_t interrupt_handle( int irq, void* dev_id, struct pt_regs* regs )
{
//        struct IIC_dev *dev = dev_id;  //一般在共享设备中会用到
		disable_irq(IRQ_EINT2);//关中断
		schedule_work(&Iic_wq);
        return IRQ_HANDLED;
}

module_init(IIC_init);
module_exit(IIC_exit);





⌨️ 快捷键说明

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