📄 hi_i2c.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 + -