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

📄 hi_i2c.c

📁 嵌入式linux系统下hi3510平台的osd开发源码
💻 C
字号:
/*  extdrv/interface/i2c/hi_i2c.c
 *
 * Copyright (c) 2006 Hisilicon Co., Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program;
 *
 * History:
 *      19-April-2006 create this file
 *      25-July-2006  when the read/write operation was wrong redo it,
 *                    but not more than 3 times
 *      19-August-2006 remove the print info of timeout,
 *                     change the read/write retry times to 5,
 *                     and if even wrong we would stop it and then print info
 */

#include <linux/module.h>
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/fcntl.h>

#include <linux/init.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/workqueue.h>

#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>

#include "hi_i2c.h"


static void __iomem *i2c_map_addr;
unsigned int I2C_BASE_MMAP;

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

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

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


#define TIMECOUNT       0x100
#define RW_RETRY_TIME   5


/*
 * 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 unsigned char i2creceivebyte(void)
{
    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(20);
        if(++i>TIMECOUNT)
        {
            /*printk("TIME OUT: i2creceivebyte\n");*/
            return -1;
        }
        I2C_REG_READW(I2C_RXFIFO_FLAG, status);

    }

    I2C_REG_READW(I2C_DATA_CMD,ucvalue);
    return(ucvalue);
}

/*
 * sends ack check routine.
 *
 * @return value:0--success; -1--error.
 *
 */
static int i2cchecksendresult(void)
{
    unsigned short status, status1;
    unsigned long i = 0;

    I2C_REG_READW(I2C_TXFIFO_FLAG, status);
    I2C_REG_READW(I2C_STATUS, status1);

    /*TX FIFO is not empty and wait for a while*/
    while((status != 0) || (status1 & 0x1))
    {
        udelay(20);
        if(++i>TIMECOUNT)
        {
            /*printk("TIME OUT: i2cchecksendresult,I2C_TXFIFO_FLAG:%d,
                    I2C_STATUS:%d \n",status, status1);*/
            return -1;
        }
        I2C_REG_READW(I2C_TXFIFO_FLAG, status);
        I2C_REG_READW(I2C_STATUS, status1);
    }
    return 0;
}

/*
 * writes address of device to I2C bus routine.
 *
 * @param address: address of device
 *
 */
static void i2csetaddress(unsigned char address)
{
    I2C_REG_WRITEW(I2C_ENABLE, 0);
    I2C_REG_WRITEW(I2C_TAR, address>>1);
    I2C_REG_WRITEW(I2C_ENABLE, 1);
}

/*
 *  read data from the I2C bus of a device rountine.
 *
 *  @param  devaddress:  address of the device
 *  @param  regaddress: address of register within device
 *
 *  @return value: data from the device readed
 *
 */
unsigned char hi_i2c_read(unsigned char devaddress, unsigned char regaddress)
{
    int rxdata, i;

    for (i = 0; i < RW_RETRY_TIME; i++)
    {
        i2csetaddress((unsigned char)(devaddress));
        i2csendbyte(regaddress);
        rxdata = i2creceivebyte();

        if (-1 != rxdata)
        {
            return rxdata;
        }
    }

    printk("I2C_READ_WRONG: timeout more than %d times and stop here. \n",RW_RETRY_TIME );
    while(1);

    return rxdata;
}

/*
 *  writes data to a device on the I2C bus rountine.
 *
 *  @param  devaddress:  address of the device
 *  @param  regaddress: address of register within device
 *  @param  data:   data for writed to device
 *
 *  @return value:0--success; -1--error.
 *
 */
int hi_i2c_write(unsigned char devaddress,unsigned char regaddress,unsigned char data)
{
    int ret, i;

    ret = 0;

    for (i = 0; i < RW_RETRY_TIME; i++)
    {
        i2csetaddress((unsigned char)(devaddress));
        i2csendbyte(regaddress);
        i2csendbyte(data);
        ret = i2cchecksendresult();

        if (0 == ret)
        {
            return ret;
        }
    }

    printk("I2C_WRITE_WRONG: timeout more than %d times and stop here. \n",RW_RETRY_TIME );
    while(1);

    /*return ret;*/
}


/*
 *  writes data to a device on the I2C bus of a special device rountine.
 *  special device example: TW2824 TW2834
 *
 *  @param  devaddress:  address of the device
 *  @param  pageindex: page address of register within device
 *  @param  regaddress: address of register within device
 *  @param  data:   data for writed to device
 *
 *  @return value:0--success; -1--error.
 *
 */
int hi_i2c_writespecial(unsigned char devaddress,unsigned char pageindex,unsigned char regaddress,unsigned char data)
{
    int ret, i;

    ret = 0;

    for (i = 0; i < RW_RETRY_TIME; i++)
    {
        i2csetaddress((devaddress));
        i2csendbyte(pageindex);
        i2csendbyte(regaddress);
        i2csendbyte(data);
        ret = i2cchecksendresult();

        if (0 == ret)
        {
            return ret;
        }
    }

    printk("I2C_WRITE_WRONG: timeout more than %d times and stop here. \n",RW_RETRY_TIME );
    while(1);

    /*return ret;*/
}

/*
 *  read data from the I2C bus of a special device rountine.
 *  special device example: TW2824 TW2834
 *
 *  @param  devaddress:  address of the device
 *  @param  pageindex: page address of register within device
 *  @param  regaddress: address of register within device
 *
 *  @return value: data from the device readed
 *
 */
unsigned char hi_i2c_readspecial(unsigned char devaddress, unsigned char pageindex,unsigned char regaddress)
{
    int rxdata, i;

    for (i = 0; i < RW_RETRY_TIME; i++)
    {
        i2csetaddress((unsigned char)(devaddress));
        i2csendbyte(pageindex);
        i2csendbyte(regaddress);
        rxdata = i2creceivebyte();

        if (-1 != rxdata)
        {
            return rxdata;
        }
    }

    printk("I2C_READ_WRONG: timeout more than %d times and stop here. \n",RW_RETRY_TIME );
    while(1);

    return rxdata;
}

static unsigned int  i2cinitialized =0;
/*
 * initializes I2C interface routine.
 *
 * @return value:0--success; -EFAULT--error.
 *
 */
static int __init hi_i2c_init(void)
{
    unsigned int cnt, hcnt, lcnt;

   if(i2cinitialized == 0)
    {
        printk(KERN_INFO "Hisilicon I2C Driver Init Start.\n");
        i2c_map_addr=(unsigned int*)ioremap(I2C_BASE,PAGE_SIZE);
        if(i2c_map_addr<0)
        {
            printk("NO mem\n");
            return -EFAULT;
        }
        I2C_BASE_MMAP = (unsigned int)i2c_map_addr;
        I2C_REG_WRITEW(I2C_ENABLE, 0);

        /*
        standard speed.
        */
        cnt = I2C_CLK/I2C_RATE;
        hcnt = (cnt/9)*4;
        lcnt = (cnt/9)*5;

        I2C_REG_WRITEW(I2C_CON, 0x0023);
        I2C_REG_WRITEW(I2C_HCNT, hcnt);
        I2C_REG_WRITEW(I2C_LCNT, lcnt);
        I2C_REG_WRITEW(I2C_INTR_MASK, 0x0000);
        i2cinitialized = 1;
        return 0;
    }
    else
    {
        printk("I2c has been initialized.\n");
        return 0;
    }
}

static void __exit hi_i2c_exit(void)
{
    iounmap((void *)i2c_map_addr);
    i2cinitialized =0;
}

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");



EXPORT_SYMBOL(hi_i2c_read);
EXPORT_SYMBOL(hi_i2c_write);
EXPORT_SYMBOL(hi_i2c_readspecial);
EXPORT_SYMBOL(hi_i2c_writespecial);

⌨️ 快捷键说明

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