linux gpio模拟I2c驱动(基于海思平台)

多字节操作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

 

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值