多字节操作bug见评论1
驱动程序:gpio_i2c.h
#ifndef _GPIO_I2C_H_
#define _GPIO_I2C_H_
typedef struct {
unsigned char dev_addr;
unsigned short reg_addr;
unsigned char addr_byte_num;
unsigned int data;
unsigned char data_byte_num;
}GPIOI2C_DATA_S;
/* 定义幻数 */
#define MEMDEV_IOC_MAGIC 'k'
/* 定义命令 */
#define GPIO_I2C_READ _IOWR(MEMDEV_IOC_MAGIC, 0x01,GPIOI2C_DATA_S)
#define GPIO_I2C_SELCHN _IOWR(MEMDEV_IOC_MAGIC, 0x05,GPIOI2C_DATA_S)
#define GPIO_I2C_WRITE _IOWR(MEMDEV_IOC_MAGIC, 0x03,GPIOI2C_DATA_S)
#define GPIO_I2C_WRITE2 _IOWR(MEMDEV_IOC_MAGIC, 0x07,GPIOI2C_DATA_S)
#define GPIO_I2C_WRITE4 _IOWR(MEMDEV_IOC_MAGIC, 0x09,GPIOI2C_DATA_S)
typedef unsigned char byte;
#define high_scl i2c_set(SCL)
#define low_scl i2c_clr(SCL)
#define high_sda i2c_set(SDA)
#define low_sda i2c_clr(SDA)
unsigned char gpio_i2c_read(unsigned char devaddress, unsigned char address);
void gpio_i2c_write(unsigned char devaddress, unsigned int address, unsigned char value);
#endif
gpio_i2c.c
#include <linux/module.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/io.h>
#include <asm/gpio.h>
#include "gpio_i2c.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));
printk(KERN_WARNING "%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);
printk(KERN_WARNING "%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);
printk(KERN_WARNING "%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()) {
printk(KERN_WARNING "%d,get a nack.\n", __LINE__);
return -1;
}
demo_i2c_send_byte(address & 0xff);
if(demo_i2c_recv_ack()) {
printk(KERN_WARNING "%d,get a nack.\n", __LINE__);
return -1;
}
for(i=0; i<len; i++) {
demo_i2c_send_byte(data);
if(demo_i2c_recv_ack()) {
printk(KERN_WARNING "%d,get a nack.\n", __LINE__);
return -1;
}
}
demo_i2c_stop();
return i;
}
#if 1
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;
}
int gpioi2c_open(struct inode *inode, struct file *file)
{
return 0;
}
int gpioi2c_close(struct inode *inode, struct file *file)
{
return 0;
}
static struct file_operations gpioi2c_fops = {
.owner = THIS_MODULE,
//.ioctl = gpioi2c_ioctl,
.unlocked_ioctl = gpioi2c_ioctl,
.open = gpioi2c_open,
.release = gpioi2c_close};
static struct miscdevice gpioi2c_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "gpioI2c",
.fops = &gpioi2c_fops,
};
static int __init 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);
ret = misc_register(&gpioi2c_dev);
if (0 != ret)
return -1;
return 0;
}
static void __exit 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);
misc_deregister(&gpioi2c_dev);
}
module_init(gpio_i2c_init);
module_exit(gpio_i2c_exit);
#ifdef MODULE
//#include <linux/compile.h>
#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("cb");
#endif
应用层:gpioApp.c
#include <stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include <linux/ioctl.h>
#pragma 0
typedef struct {
unsigned char dev_addr;
unsigned short reg_addr;
unsigned char addr_byte_num;
unsigned int data;
unsigned char data_byte_num;
}GPIOI2C_DATA_S;
/* 定义幻数 */
#define MEMDEV_IOC_MAGIC 'k'
/* 定义命令 */
#define GPIO_I2C_READ _IOWR(MEMDEV_IOC_MAGIC, 0x01,GPIOI2C_DATA_S)
#define GPIO_I2C_SELCHN _IOWR(MEMDEV_IOC_MAGIC, 0x05,GPIOI2C_DATA_S)
#define GPIO_I2C_WRITE _IOWR(MEMDEV_IOC_MAGIC, 0x03,GPIOI2C_DATA_S)
#define GPIO_I2C_WRITE2 _IOWR(MEMDEV_IOC_MAGIC, 0x07,GPIOI2C_DATA_S)
#define GPIO_I2C_WRITE4 _IOWR(MEMDEV_IOC_MAGIC, 0x09,GPIOI2C_DATA_S)
int main()
{
int fd = 0;
int cmd;
GPIOI2C_DATA_S arg ;
char Buf[4096];
/*打开设备文件*/
fd = open("/dev/gpioI2c",O_RDWR);
if (fd < 0)
{
printf("Open Dev Mem0 Error!\n");
return -1;
}
arg.addr_byte_num=0x00;
arg.data_byte_num=0x00;
arg.dev_addr=0x8c;
arg.reg_addr=0x3a;
arg.data=0x80;
cmd = GPIO_I2C_WRITE;
if (ioctl(fd, cmd, &arg) < 0)
{
printf("Call cmd MEMDEV_IOCPRINT fail\n");
return -1;
}
arg.addr_byte_num=0x00;
arg.data_byte_num=0x00;
arg.dev_addr=0x8c;
arg.reg_addr=0x3a;
arg.data=0x00;
cmd = GPIO_I2C_READ;
if (ioctl(fd, cmd, &arg) < 0)
{
printf("Call cmd MEMDEV_IOCPRINT fail\n");
return -1;
}
printf("read--device_addr:0x%02x reg_addr:0x%02x reg_val:0x%02x\n", arg.dev_addr, arg.reg_addr, arg.data);
arg.addr_byte_num=0x00;
arg.data_byte_num=0x00;
arg.dev_addr=0x8c;
arg.reg_addr=0x3a;
arg.data=0x13;
cmd = GPIO_I2C_WRITE;
if (ioctl(fd, cmd, &arg) < 0)
{
printf("Call cmd MEMDEV_IOCPRINT fail\n");
return -1;
}
arg.addr_byte_num=0x00;
arg.data_byte_num=0x00;
arg.dev_addr=0x8c;
arg.reg_addr=0x3a;
arg.data=0x00;
cmd = GPIO_I2C_READ;
if (ioctl(fd, cmd, &arg) < 0)
{
printf("Call cmd MEMDEV_IOCPRINT fail\n");
return -1;
}
printf("read1--device_addr:0x%02x reg_addr:0x%02x reg_val:0x%02x\n", arg.dev_addr, arg.reg_addr, arg.data);
close(fd);
return 0;
}
Makefile
obj-m += gpio_i2c.o
KDIR :=/home/dream/hi3556/Hi3559V200_SDK_V2.0.0.2/osdrv/opensource/kernel/linux-4.9.y-smp
PWD = $(shell pwd)
all:
make ARCH=arm CROSS_COMPILE=arm-himix200-linux- -C $(KDIR) M=$(PWD) modules
arm-himix200-linux-gcc -o gpioApp gpioApp.c
cp gpio_i2c.ko gpioApp ~/share/视频上传
clean:
make -C $(KDIR) M=$(PWD) clean