📄 gpio_i2c.c
字号:
/*
* extdrv/interface/gpio_i2c/gpio_i2c.c
*/
#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 "gpio_i2c.h"
static void __iomem *gpio_map_addr;
unsigned int GPIO_BASE_MMAP;
/* GPIO1_1 */
#define SCL (1 << 0)
/* GPIO1_0 */
#define SDA (1 << 1)
#define BIT0 0x01
#define BIT1 0x02
#define GPIO_1_BASE 0x101e5000 //Hi3510 决定的,gpio1的基址
#define GPIO_1_DIR (GPIO_BASE_MMAP + 0x400)//0x4000:GPIO_DIR(方向控制寄存器)的偏移地址
#define GPIO_I2C_SDA_REG (GPIO_BASE_MMAP + 0x04)//gpio1 GPIO_DATA的bit[0]
#define GPIO_I2C_SCL_REG (GPIO_BASE_MMAP + 0x08)//gpio1 GPIO_DATA的bit[1]
#define GPIO_I2C_SCLSDA_REG (GPIO_BASE_MMAP + 0x0c)
#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_1_DIR);
regvalue |= BIT1;
HW_REG(GPIO_1_DIR) = regvalue;
HW_REG(GPIO_I2C_SCL_REG) = 0;
return;
}
else if(whichline == SDA)
{
regvalue = HW_REG(GPIO_1_DIR);
regvalue |= BIT0;
HW_REG(GPIO_1_DIR) = regvalue;
HW_REG(GPIO_I2C_SDA_REG) = 0;
return;
}
else if(whichline == (SDA|SCL))
{
regvalue = HW_REG(GPIO_1_DIR);
regvalue |= BIT0 | BIT1;
HW_REG(GPIO_1_DIR) = regvalue;
HW_REG(GPIO_I2C_SCLSDA_REG) = 0;
return;
}
else
{
printk("Error input.\n");
return;
}
}
/*
* 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_1_DIR);
regvalue |= BIT1;
HW_REG(GPIO_1_DIR) = regvalue;
HW_REG(GPIO_I2C_SCL_REG) = BIT1;
return;
}
else if(whichline == SDA)
{
regvalue = HW_REG(GPIO_1_DIR);
regvalue |= BIT0;
HW_REG(GPIO_1_DIR) = regvalue;
HW_REG(GPIO_I2C_SDA_REG) = BIT0;
return;
}
else if(whichline == (SDA|SCL))
{
regvalue = HW_REG(GPIO_1_DIR);
regvalue |= BIT0 | BIT1;
HW_REG(GPIO_1_DIR) = regvalue;
HW_REG(GPIO_I2C_SCLSDA_REG) = BIT0 | BIT1;
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)
{
int i,j;
for(i=0;i<usec * 5;i++)
{
for(j=0;j<47;j++)
{;}
}
}
/*
* 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_1_DIR);
regvalue &= ~BIT0; //bit0清0,使SDA的方向为读入
HW_REG(GPIO_1_DIR) = regvalue;
DELAY(1);
regvalue = HW_REG(GPIO_I2C_SDA_REG);//读SDA,bit0
if((regvalue & BIT0) != 0)
return 1;
else
return 0;
}
/*
* sends a start bit via I2C rountine.
*/
static void i2c_start_bit(void)
{
DELAY(1);
i2c_set(SDA | SCL);
DELAY(1);
i2c_clr(SDA);//SCL 为高时SDA由高变低
DELAY(1);
}
/*
* sends a stop bit via I2C rountine.
*/
static void i2c_stop_bit(void)
{
/* clock the ack */
DELAY(1);
i2c_set(SCL);
DELAY(1);
i2c_clr(SCL);
/* actual stop bit */
DELAY(1);
i2c_clr(SDA);
DELAY(1);
i2c_set(SCL);
DELAY(1);
i2c_set(SDA);//SCL为高时SDA由低变高
DELAY(1);
}
/*
* sends a character over I2C rountine.
* @param c: character to send
*/
static void i2c_send_byte(unsigned char c)
{
int i;
for (i=0; i<8; i++)
{
DELAY(1);
i2c_clr(SCL);
DELAY(1);
if (c & (1<<(7-i)))//相应位为1
i2c_set(SDA);
else //相应位为0
i2c_clr(SDA);
DELAY(1);
i2c_set(SCL);
DELAY(1);
i2c_clr(SCL);
}
DELAY(1);
i2c_set(SDA);//释放对SDA的控制权//////////
DELAY(1); ////////////////////////////
}
/* receives a character from I2C rountine.
* @return value: character received
*/
static unsigned char i2c_receive_byte(void)
{
int j=0;
int i;
unsigned char regvalue;
i2c_set(SDA);
for (i=0; i<8; i++)
{
DELAY(1);
i2c_clr(SCL);
DELAY(1);
i2c_set(SCL);
regvalue = HW_REG(GPIO_1_DIR);
regvalue &= ~BIT0;
HW_REG(GPIO_1_DIR) = regvalue;//与i2c_data_read函数重复
DELAY(1);
if (i2c_data_read())
j+=(1<<(7-i));
DELAY(1);
i2c_clr(SCL);
}
DELAY(1);
i2c_clr(SDA);///////////////////
DELAY(1);////////////////////
return j;
}
/* receives an acknowledge from I2C rountine.
*
* @return value: 0--Ack received; 1--Nack received 接收到高电平表示从设备接收成功。
*
*/
static int i2c_receive_ack(void)
{
int nack;
unsigned char regvalue;
DELAY(1);
regvalue = HW_REG(GPIO_1_DIR);
regvalue &= ~BIT0;
HW_REG(GPIO_1_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);
i2c_set(SDA);///////////////
DELAY(1); /////////////////////
if (nack == 0)//1:Ack, 0:Nack
return 1;
return 0;
}
/*
* sends an acknowledge over I2C rountine.
* 发送高电平
*/
static void i2c_send_ack(void)
{
DELAY(1);
i2c_clr(SCL);
DELAY(1);
i2c_set(SDA);//发送高电平
DELAY(1);
i2c_set(SCL);
DELAY(1);
i2c_clr(SCL);
DELAY(1);
i2c_clr(SDA);
DELAY(1);
}
/*
* read data from the I2C bus by GPIO simulated of a device rountine.
* @param devaddress: address of the device
* @param address: address of register within device
*
* @return value: data from the device readed
*
*/
unsigned char gpio_i2c_read(unsigned char devaddress, unsigned char address)
{
int rxdata;
i2c_start_bit();
i2c_send_byte((unsigned char)(devaddress));
i2c_receive_ack();
i2c_send_byte(address);
i2c_receive_ack();
i2c_start_bit();
i2c_send_byte((unsigned char)(devaddress) | 1);
i2c_receive_ack();
rxdata = i2c_receive_byte();
i2c_send_ack();
i2c_stop_bit();
return rxdata;
}
/*
* read data from the I2C bus by GPIO simulated of a digital camera device rountine.
*
* @param devaddress: address of the device
* @param address: address of register within device
*
*/
unsigned char gpio_sccb_read(unsigned char devaddress, unsigned char address)
{
int rxdata;
i2c_start_bit();
i2c_send_byte((unsigned char)(devaddress));
i2c_receive_ack();
i2c_send_byte(address);
i2c_receive_ack();
i2c_stop_bit();
i2c_start_bit();
i2c_send_byte((unsigned char)(devaddress) | 1);
i2c_receive_ack();
rxdata = i2c_receive_byte();
i2c_send_ack();
i2c_stop_bit();
return rxdata;
}
/*
* writes data to a device on the I2C bus rountine.
*
* @param devaddress: address of the device
* @param address: address of register within device
* @param data: data for write to device
*
*/
void gpio_i2c_write(unsigned char devaddress, unsigned char address, unsigned char data)
{
i2c_start_bit();
i2c_send_byte((unsigned char)(devaddress));
i2c_receive_ack();
i2c_send_byte(address);
i2c_receive_ack();
i2c_send_byte(data);
i2c_stop_bit();
}
static unsigned int gpioinitialized =0;
/*
* initializes I2C interface routine.
*
* @return value:0--success; 1--error.
*
*/
static int __init gpio_i2c_init(void)
{
if(gpioinitialized == 0)
{
gpio_map_addr = (unsigned int*)ioremap(GPIO_1_BASE,PAGE_SIZE);//将I/O内存空间映射到核心虚拟地址空间,PAGE_SIZE:每一页内存的大小,在asm/page.h中定义。
if(gpio_map_addr<0)
{
printk("NO mem\n");
return -EFAULT;
}
GPIO_BASE_MMAP = (unsigned int)gpio_map_addr;
i2c_clr(SCL | SDA);
printk(KERN_INFO "GPIO control for I2C Driver init successful.\n");
gpioinitialized =1;
return 0;
}
else
{
printk("GPIO control for I2C has been initialized.\n");
return 0;
}
}
static void __exit gpio_i2c_exit(void)
{
iounmap((void *)gpio_map_addr);
gpioinitialized =0;
}
module_init(gpio_i2c_init);
module_exit(gpio_i2c_exit);
#ifdef MODULE
#include <linux/compile.h>
#endif
MODULE_INFO(build, UTS_VERSION);
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(gpio_i2c_read);
EXPORT_SYMBOL(gpio_sccb_read);
EXPORT_SYMBOL(gpio_i2c_write);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -