理论所有linux都可以使用。在文件i2c_hibvt.c改为。下面的代码主要修改GPIO_15_BASE SCL_SHIFT_NUM,修改makefile kconfig保证代码被编译
#include <linux/errno.h>
#include "i2c_hibvt.h"
#define demo_delay time_delay_us(2)
#ifdef HI_FPGA
#define GPIO_15_BASE 0x12240000
#define SCL_SHIFT_NUM 2
#define SDA_SHIFT_NUM 3
#define SCL (0x1 << SCL_SHIFT_NUM) /* GPIO7 0_7 */
#define SDA (0x1 << SDA_SHIFT_NUM) /* GPIO7 0_6 */
#define GPIO_I2C_SCL_REG IO_ADDRESS(GPIO_15_BASE + (0x1 << (SCL_SHIFT_NUM + 2))) /* 0x200 */
#define GPIO_I2C_SDA_REG IO_ADDRESS(GPIO_15_BASE + (0x1 << (SDA_SHIFT_NUM + 2))) /* 0x100 */
#define GPIO_I2C_SCLSDA_REG IO_ADDRESS(GPIO_15_BASE + ((0x1 << (SCL_SHIFT_NUM + 2)) + (0x1 << (SDA_SHIFT_NUM + 2)))) /* 0x300 need check */
#else
/*记得修改Makefile里面的路径*/
/*下面需要修改为对应芯片的*/
#define GPIO_15_BASE 0x120b1000
#define SCL_SHIFT_NUM 4
#define SDA_SHIFT_NUM 5
/*上面需要修改为对应芯片的*/
#define SCL (0x1 << SCL_SHIFT_NUM) /* GPIO1 0_7 */
#define SDA (0x1 << SDA_SHIFT_NUM) /* GPIO1 0_6 */
void * GPIO_I2C_SCL_REG;
void * GPIO_I2C_SDA_REG;
void * GPIO_I2C_SCLSDA_REG; /* 0x300 need check */
#endif
void *GPIO_0_DIR;
#define HW_REG(reg) *((volatile unsigned int *)(reg))
#define DELAY(us) time_delay_us(us)
/*
* I2C by GPIO simulated clear 0 routine.
*
* @param whichline: GPIO control line
*
*/
static void i2c_clr(unsigned char whichline)
{
unsigned char regvalue;
if (whichline == SCL)
{
regvalue = HW_REG(GPIO_0_DIR);
regvalue |= SCL;
HW_REG(GPIO_0_DIR) = regvalue;
HW_REG(GPIO_I2C_SCL_REG) = 0;
return;
}
else if (whichline == SDA)
{
regvalue = HW_REG(GPIO_0_DIR);
regvalue |= SDA;
HW_REG(GPIO_0_DIR) = regvalue;
HW_REG(GPIO_I2C_SDA_REG) = 0;
return;
}
else if (whichline == (SDA | SCL))
{
regvalue = HW_REG(GPIO_0_DIR);
regvalue |= (SDA | SCL);
HW_REG(GPIO_0_DIR) = regvalue;
HW_REG(GPIO_I2C_SCLSDA_REG) = 0;
return;
}
else
{
printk("Error input.\n");
return;
}
}
/*
* delays for a specified number of micro seconds rountine.
*
* @param usec: number of micro seconds to pause for
*
*/
void time_delay_us(unsigned int usec)
{
// volatile int i,j;
#ifdef HI_FPGA
for (i = 0; i < usec * 5; i++)
{
for (j = 0; j < 47; j++)
{
;
}
}
#else
udelay(usec * 60);
#endif
}
/*
* I2C by GPIO simulated set 1 routine.
*
* @param whichline: GPIO control line
*
*/
static void i2c_set(unsigned char whichline)
{
unsigned char regvalue;
if (whichline == SCL)
{
regvalue = HW_REG(GPIO_0_DIR);
regvalue |= SCL;
HW_REG(GPIO_0_DIR) = regvalue;
HW_REG(GPIO_I2C_SCL_REG) = SCL;
return;
}
else if (whichline == SDA)
{
regvalue = HW_REG(GPIO_0_DIR);
regvalue |= SDA;
HW_REG(GPIO_0_DIR) = regvalue;
HW_REG(GPIO_I2C_SDA_REG) = SDA;
return;
}
else if (whichline == (SDA | SCL))
{
regvalue = HW_REG(GPIO_0_DIR);
regvalue |= (SDA | SCL);
HW_REG(GPIO_0_DIR) = regvalue;
HW_REG(GPIO_I2C_SCLSDA_REG) = (SDA | SCL);
return;
}
else
{
printk("Error input.\n");
return;
}
}
/*
* I2C by GPIO simulated read data routine.
*
* @return value: a bit for read
*
*/
static unsigned char i2c_data_read(void)
{
unsigned char regvalue;
regvalue = HW_REG(GPIO_0_DIR);
regvalue &= (~SDA);
HW_REG(GPIO_0_DIR) = regvalue;
DELAY(1);
regvalue = HW_REG(GPIO_I2C_SDA_REG);
if ((regvalue & SDA) != 0)
return 1;
else
return 0;
}
static void demo_i2c_start(void)
{
// //out_scl();
// //out_sda();
high_scl;
high_sda;
demo_delay;
low_sda;
demo_delay;
low_scl;
}
static void demo_i2c_stop(void)
{
//out_scl();
//out_sda();
high_scl;
low_sda;
demo_delay;
high_sda;
demo_delay;
low_scl;
}
/*
* sends a character over I2C rountine.
*
* @param c: character to send
*
*/
static void demo_i2c_send_byte(unsigned char data)
{
int i = 0;
//out_scl();
//out_sda();
low_scl;
for(i=0;i<8;i++) {
if(data & (0x80>>i))
high_sda;
else
low_sda;
demo_delay;
high_scl;
demo_delay;
low_scl;
}
}
/* receives a character from I2C rountine.
*
* @return value: character received
*
*/
static unsigned char demo_i2c_recv_byte(void)
{
int i = 0;
unsigned char data = 0;
//out_scl();
//in_sda();
low_scl;
for(i=0;i<8;i++) {
demo_delay;
high_scl;
demo_delay;
data <<= 1;//循环8次,最终只左移了7次
data |= i2c_data_read();
low_scl;
}
return data;
}
/* receives an acknowledge from I2C rountine.
*
* @return value: 0--Ack received; 1--Nack received
*
*/
static unsigned char demo_i2c_recv_ack(void)
{
int nack;
unsigned char regvalue;
regvalue = HW_REG(GPIO_0_DIR);
regvalue &= (~SDA);
HW_REG(GPIO_0_DIR) = regvalue;
//DELAY(1);
i2c_clr(SCL);
DELAY(1);
i2c_set(SCL);
DELAY(1);
nack = i2c_data_read();
DELAY(1);
i2c_clr(SCL);
DELAY(1);
if (nack == 0)
{
return 0;
}
else
{
return 1;
}
}
static void demo_i2c_send_ack(unsigned char ack)
{
//out_scl();
//out_sda();
low_scl;
if(ack)
high_sda;
else
low_sda;
demo_delay;
high_scl;
demo_delay;
low_scl;
}
EXPORT_SYMBOL(gpio_i2c_read);
unsigned char gpio_i2c_read(unsigned char devaddress, unsigned char address)
{
int i = 0,len=1;
char buff;
demo_i2c_start();
demo_i2c_send_byte((unsigned char)(devaddress));
if(demo_i2c_recv_ack()) {
printk("data:0x%02x\n",(unsigned char)(devaddress));
printf( "%d,get a nack.\n", __LINE__);
return -1;
}
demo_i2c_send_byte(address & 0xff);
if(demo_i2c_recv_ack()) {
printk("address:0x%02x\n",address & 0xff);
printf( "%d,get a nack.\n", __LINE__);
return -1;
}
demo_i2c_start();
demo_i2c_send_byte((unsigned char)(devaddress) | 1);
if(demo_i2c_recv_ack()) {
printk("devaddress:0x%02x\n",(unsigned char)(devaddress) | 1);
printf( "%d,get a nack.\n", __LINE__);
return -1;
}
for(i=0; i<(len-1); i++) {
buff = demo_i2c_recv_byte();
demo_i2c_send_ack(0);
}
buff = demo_i2c_recv_byte();
demo_i2c_send_ack(1);
demo_i2c_stop();
return buff;
}
EXPORT_SYMBOL(gpio_i2c_write);
void gpio_i2c_write(unsigned char devaddress, unsigned int address, unsigned char data)
{
int i = 0,len=1;
demo_i2c_start();
demo_i2c_send_byte((unsigned char)(devaddress));
if(demo_i2c_recv_ack()) {
printf( "%d,get a nack.\n", __LINE__);
return -1;
}
demo_i2c_send_byte(address & 0xff);
if(demo_i2c_recv_ack()) {
printf( "%d,get a nack.\n", __LINE__);
return -1;
}
for(i=0; i<len; i++) {
demo_i2c_send_byte(data);
if(demo_i2c_recv_ack()) {
printf( "%d,get a nack.\n", __LINE__);
return -1;
}
}
demo_i2c_stop();
return i;
}
#if 0
long gpioi2c_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret;
unsigned char device_addr;
unsigned int reg_addr;
unsigned int reg_val;
GPIOI2C_DATA_S i2c_data_t;
switch (cmd)
{
case GPIO_I2C_READ:
ret=copy_from_user(&i2c_data_t, (GPIOI2C_DATA_S *)arg, sizeof(GPIOI2C_DATA_S));
device_addr = i2c_data_t.dev_addr;
reg_addr = i2c_data_t.reg_addr;
i2c_data_t.data = gpio_i2c_read(device_addr, reg_addr);
printk("GPIO_I2C_READ--device_addr:0x%02x reg_addr:0x%02x reg_val:0x%02x\n", device_addr, reg_addr, i2c_data_t.data);
ret=copy_to_user((GPIOI2C_DATA_S *)arg, &i2c_data_t, sizeof(GPIOI2C_DATA_S));
break;
case GPIO_I2C_SELCHN:
break;
case GPIO_I2C_WRITE:
ret=copy_from_user(&i2c_data_t, (GPIOI2C_DATA_S *)arg, sizeof(GPIOI2C_DATA_S));
device_addr = i2c_data_t.dev_addr;
reg_addr = i2c_data_t.reg_addr;
reg_val = i2c_data_t.data;
gpio_i2c_write(device_addr, reg_addr, reg_val);
break;
case GPIO_I2C_WRITE2:
ret=copy_from_user(&i2c_data_t, (GPIOI2C_DATA_S *)arg, sizeof(GPIOI2C_DATA_S));
break;
case GPIO_I2C_WRITE4:
ret=copy_from_user(&i2c_data_t, (GPIOI2C_DATA_S *)arg, sizeof(GPIOI2C_DATA_S));
break;
default:
printk("error!!%d\n", cmd);
return -1;
}
return 0;
}
#endif
int gpioi2c_open(struct inode *inode, struct file *file)
{
return 0;
}
int gpioi2c_close(struct inode *inode, struct file *file)
{
return 0;
}
int gpio_i2c_init(void)
{
int ret;
//unsigned int reg;
GPIO_0_DIR=ioremap(GPIO_15_BASE + 0x400, 1); /* GPIO direction reg */
GPIO_I2C_SCL_REG=ioremap(GPIO_15_BASE + (0x1 << (SCL_SHIFT_NUM + 2)), 1); /* 0x200 */
GPIO_I2C_SDA_REG=ioremap(GPIO_15_BASE + (0x1 << (SDA_SHIFT_NUM + 2)), 1);
GPIO_I2C_SCLSDA_REG=ioremap(GPIO_15_BASE + ((0x1 << (SCL_SHIFT_NUM + 2)) + (0x1 << (SDA_SHIFT_NUM + 2))), 1);
return 0;
}
void gpio_i2c_exit(void)
{
iounmap(GPIO_0_DIR); /* GPIO direction reg */
iounmap(GPIO_I2C_SCL_REG); /* 0x200 */
iounmap(GPIO_I2C_SDA_REG);
iounmap(GPIO_I2C_SCLSDA_REG);
}