Hi3519v101 i2c r8010 rtc驱动

25 篇文章 0 订阅
2 篇文章 0 订阅

一、相关文件

Hi3519v101 i2c 总线驱动文件路径:

drivers/i2c/busses/i2c-hisi-v110.c

 

二、调试测试

1、在调试过程中遇到一个小问题,详见链接

2、驱动只实现了读秒寄存器

3、i2c/i2c_rtc_dev.c

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/i2c.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>


// gpio1_6 → i2c2_sda 0x1204005c set 0x01
// gpio1_7 → i2c2_scl 0x12040060 set 0x01
#define i2c2_sda_base 0x1204005c //gpio管脚复用物理地址
#define i2c2_scl_base 0x12040060 //gpio管脚复用物理地址

#define gpio_phy_data 0x010		//gpio管脚数据偏移地址,0b00_0001_0000
#define gpio_phy_dir 0x400		//管脚方向寄存器偏移地址
#define gpio_out 0x4 //gpio3_2 配置为输出,1输出 0输入def
#define gpio_out_h 0xFF
#define gpio_out_l 0x00

static void __iomem *i2c2_sda; //寄存器基地址
static void __iomem *i2c2_scl; //寄存器基地址

static struct i2c_board_info r8010_dev_info = {
    //所支持的i2c设备的列表
    I2C_BOARD_INFO("r8010", 0x32), //一项代表一个支持的设备,它的名字叫做“r8010”,器件的地址是0x32,注意这是7位地址!
                                   //在海思i2c 0x0004 I2C_TAR[9:0]位有说明,如果slave地址长度位设置为7bit,则仅bit[6:0]有效!
                                   //例如,r8010 8bit读地址为0x64,则7bit地址为0x32
};

static struct i2c_client *r8010_client;

static int __init r8010_dev_init(void)
{
    struct i2c_adapter *i2c_adap; //分配一个适配器的指针

    i2c_adap = i2c_get_adapter(2);                            //调用core层的函数,获得一个i2c总线。这里我们已经知道新增的器件挂接在编号为0的i2c总线上
    r8010_client = i2c_new_device(i2c_adap, &r8010_dev_info); // 把i2c适配器和新增的I2C器件关联起来,这个用了i2c总线2,地址是0x64。这就组成了一个客户端
    i2c_put_adapter(i2c_adap);

    //管脚复用配置
    i2c2_sda = ioremap(i2c2_sda_base, 4);//4个字节,32位
    i2c2_scl = ioremap(i2c2_scl_base, 4);

    // val = ioread32(i2c2_sda);
    // val &= ~(0x01 << 0)
    iowrite32(0x01, i2c2_sda);
    iowrite32(0x01, i2c2_scl);

    return 0;
}

static void __exit r8010_dev_exit(void)
{
    i2c_unregister_device(r8010_client);
}

module_init(r8010_dev_init);
module_exit(r8010_dev_exit);
MODULE_LICENSE("GPL");

4、i2c/i2c_rtc_drv.c

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/i2c.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define r8010_cnt 1
#define r8010_name "r8010_rtc"
#define r8010_esc_reg 0x10 //秒数寄存器

struct r8010_dev
{
    dev_t devid;            /* 设备号 	 */
    struct cdev cdev;       /* cdev 	*/
    struct class *class;    /* 类 		*/
    struct device *device;  /* 设备 	 */
    struct device_node *nd; /* 设备节点 */
    int major;              /* 主设备号 */
    void *private_data;     /* 私有数据 */
    u8 val;                 /* 三个光传感器数据 */
};

struct r8010_dev r8010dev;

//从r8010读取多个寄存器数据
static int r8010_read_regs(struct r8010_dev *dev, u8 reg, void *val, int len)
{
    int ret;
    struct i2c_msg msg[2];
    struct i2c_client *client = (struct i2c_client *)dev->private_data;

    //msg[0]为发送要读取的首地址
    msg[0].addr = client->addr; //r8010 地址
    msg[0].flags = 0;           //标志为发送数据
    msg[0].buf = &reg;          //读取的首地址
    msg[0].len = 1;             //reg长度

    //msg[1]为读取数据
    msg[1].addr = client->addr; //r8010 地址
    msg[1].flags = I2C_M_RD;    //标志为读数据
    msg[1].buf = val;           //读取数据缓冲区
    msg[1].len = len;           //要读取数据长度

    //    printk("r8010 addr= %x\n", client->addr);

    ret = i2c_transfer(client->adapter, msg, 2);
    if (ret == 2)
        ret = 0;
    else
    {
        printk("i2c read failed=%d reg=%06x len=%d\n", ret, reg, len);
        ret = -EREMOTEIO;
    }
    return ret;
}

//从r8010写入多个寄存器数据
static s32 r8010_write_regs(struct r8010_dev *dev, u8 reg, u8 *buf, int len)
{
    u8 b[256];
    struct i2c_msg msg;
    struct i2c_client *client = (struct i2c_client *)dev->private_data;

    b[0] = reg;              //寄存器首地址
    memcpy(&b[1], buf, len); //将要写入数据拷贝到b
    msg.addr = client->addr; //r8010 地址
    msg.flags = 0;           //标志为发送数据
    msg.buf = b;             //要写入的数据
    msg.len = len + 1;       //reg长度

    return i2c_transfer(client->adapter, &msg, 1);
}

//从r8010读取一个寄存器数据
static unsigned char r8010_read_reg(struct r8010_dev *dev, u8 reg)
{
    u8 data;

    r8010_read_regs(dev, reg, &data, 1);
    return data;
}

static unsigned char r8010_write_reg(struct r8010_dev *dev, u8 reg, u8 *buf)
{
    r8010_write_regs(dev, reg, buf, 1);
    return 0;
}

static ssize_t r8010_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{
    struct r8010_dev *dev = (struct r8010_dev *)filp->private_data;

    r8010dev.val = r8010_read_reg(dev, r8010_esc_reg);
    // printk("SEC reg data = %d\n", r8010dev.val);

    __copy_to_user(buf, &r8010dev.val, cnt);

    return 0;
}

static ssize_t r8010_write(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{
    struct r8010_dev *dev = (struct r8010_dev *)filp->private_data;

    __copy_from_user(&r8010dev.val, buf, 1);
    r8010_write_reg(dev, r8010_esc_reg, &r8010dev.val);

    return 0;
}

static int r8010_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &r8010dev;

    return 0;
}

static int r8010_release(struct inode *inode, struct file *filp)
{
    return 0;
}

static const struct file_operations r8010_ops = {
    .owner = THIS_MODULE,
    .open = r8010_open,
    .write = r8010_write,
    .read = r8010_read,
    .release = r8010_release,
};

static int r8010_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    //设备号
    if (r8010dev.major)
    {
        r8010dev.devid = MKDEV(r8010dev.major, 0);
        register_chrdev_region(r8010dev.devid, r8010_cnt, r8010_name);
    }
    else
    {
        alloc_chrdev_region(&r8010dev.devid, 0, r8010_cnt, r8010_name);
        r8010dev.major = MAJOR(r8010dev.devid);
    }

    //注册设备
    cdev_init(&r8010dev.cdev, &r8010_ops);
    cdev_add(&r8010dev.cdev, r8010dev.devid, r8010_cnt);

    //创建类
    r8010dev.class = class_create(THIS_MODULE, r8010_name);
    if (IS_ERR(r8010dev.class))
    {
        return PTR_ERR(r8010dev.class);
    }

    //创建设备
    r8010dev.devid = device_create(r8010dev.class, NULL, r8010dev.devid, NULL, r8010_name);
    if (IS_ERR(r8010dev.device))
    {
        return PTR_ERR(r8010dev.device);
    }

    r8010dev.private_data = client;

    return 0;
}

static int r8010_remove(struct i2c_client *client)
{
    //删除设备
    cdev_del(&r8010dev.cdev);
    unregister_chrdev_region(r8010dev.devid, r8010_cnt);

    // 注销掉类和设备
    device_destroy(r8010dev.class, r8010dev.devid);
    class_destroy(r8010dev.class);
    return 0;
}

/* 传统匹配方式ID列表 */
static const struct i2c_device_id r8010_id[] = {
    {"r8010", 0},
    {}};

static struct i2c_driver r8010_driver = {
    .probe = r8010_probe,
    .remove = r8010_remove,
    .driver = {
        .owner = THIS_MODULE,
        .name = "r8010",
    },
    .id_table = r8010_id,
};

static int __init r8010_drv_init(void)
{
    int ret;

    ret = i2c_add_driver(&r8010_driver);
    printk("ret = %d\n", ret);

    return 0;
}

static void __exit r8010_drv_exit(void)
{
    i2c_del_driver(&r8010_driver);
}

module_init(r8010_drv_init);
module_exit(r8010_drv_exit);
MODULE_LICENSE("GPL");

5、i2c/test_i2c_rtc.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main(int argc, char **argv)
{
	int fd;
	unsigned char val;
 
	fd = open("/dev/r8010_rtc", O_RDWR);	//打开设备
 
    if(fd < 0)
        printf("can`t open!\n");

	if(argc != 2)
	{
		printf("Usage :\n");
		printf("%s <read|write>\n", argv[0]);
		return 0;
	}

	if (strcmp(argv[1], "read") == 0)
	{
		read(fd, &val, 1);
		printf("read r8010 sec reg val= %x\n", val);
	}
	else
	{
		val = 0x10;
		write(fd, &val, 1);
		read(fd, &val, 1);
		printf("r8010 sec reg:\nwrite 0x10\n");
		printf("read 0x%x\n", val);
	}

	printf("\n\n");
	printf("sec = \33[s\33[?25l");//\33[s 保存现在光标的位置,\33[?25l 隐藏光标

	while (1)
	{
		read(fd, &val, 1);//这里直接死循环读取秒寄存器
		printf("\33[u%x", val);//\33[u 恢复光标位置
	}
	

	return 0;
}

6、测试


/ # insmod i2c_rtc_drv.ko
ret = 0
/ # insmod i2c_rtc_dev.ko
/ #
/ # ls /sys/bus/i2c/
devices/           drivers_autoprobe  uevent
drivers/           drivers_probe
/ # ls /sys/bus/i2c/devices/
2-0032/  i2c-0/   i2c-1/   i2c-2/   i2c-3/
/ # ls /sys/bus/i2c/devices/2-0032/name
/sys/bus/i2c/devices/2-0032/name
/ # cat /sys/bus/i2c/devices/2-0032/name
r8010
/ # ls /dev/r8010_rtc
/dev/r8010_rtc
/ # ./test_i2c_rtc read
read r8010 sec reg val= 15

sec = 19
/ #
/ # ./test_i2c_rtc write
r8010 sec reg:
write 0x10
read 0x10


sec = 13
/ #

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值