lowermachine/source/linux_driver/encoder.c
Miaow 6449ebeeac refactor(app, drv): 移植下位机的应用程序到新的通信协议
1. 应用程序实现了心跳包
2. 应用程序实现了4个相机的单独设置
3. 应用程序去除了有关喷阀、接收处理mask和硬件fifo相关的代码
4. 删除了fifo相关驱动程序
5. 修正了encoder驱动程序中的清除缓存逻辑

Co-authored-by: lyz <1942503466@qq.com>
2023-05-27 23:01:10 +08:00

326 lines
10 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/cdev.h>
#define ENCODER_CNT 1
#define ENCODER_NAME "encoder"
#define ENCODER_CMD_FUNCTION_CLEAR 1
#define ENCODER_CMD_FUNCTION_VIRT_INPUT 2
#define ENCODER_CMD_INPUT_MODE_EXTERNEL 100
#define ENCODER_CMD_INPUT_MODE_INTERNEL 101
#define ENCODER_CMD_CLEAR_MODE_BOTH 200
#define ENCODER_CMD_CLEAR_MODE_INTERNAL 201
/*
* 相关寄存器地址定义
*/
#define ENCODER_REG_BASE 0x43C10000
#define ENCODER_REG_0_OFFSET 0x00000000
#define ENCODER_REG_1_OFFSET 0x00000004
#define ENCODER_REG_2_OFFSET 0x00000008
#define ENCODER_REG_3_OFFSET 0x0000000C
#define ENCODER_REG_4_OFFSET 0x00000010
#define ENCODER_REG_5_OFFSET 0x00000014
#define ENCODER_REG_6_OFFSET 0x00000018
#define ENCODER_REG_7_OFFSET 0x0000001C
#define ENCODER_CR_ICO_MASK ((u32)(1 << 3)) // 仅限内部清除缓存 (Iternal Clear Only) 0: 允许外部输入和CLR位共同控制清除缓存1 仅允许CLR位清除缓存
#define ENCODER_CR_VTS_MASK ((u32)(1 << 2)) // 内部触发信号 (Virtual Triggle Signal) MOD位置1时由上位机软件写入将该位信号作为触发信号
#define ENCODER_CR_MOD_MASK ((u32)(1 << 1)) // 模式选择 (Mode) 0: 外部触发模式,外部触发编码器转动, 1: 内部触发模式,上位机软件模拟触发信号
#define ENCODER_CR_CLR_MASK ((u32)(1 << 0)) // 清除缓存 (Clear) 清除编码和分频控制器内部的分频计数值不影响VDIV和CDIV
static void __iomem *encoder_cr_addr;
static void __iomem *encoder_vdivr_addr;
static void __iomem *encoder_cdivra_addr;
static void __iomem *encoder_cdivrb_addr;
static void __iomem *encoder_cdivrc_addr;
static void __iomem *encoder_cdivrd_addr;
struct encoder_dev
{
dev_t devid;
struct cdev cdev;
struct class *class;
struct device *device;
int major;
int minor;
};
typedef struct
{
u32 valve_divide_value;
u32 camera_a_divide_value;
u32 camera_b_divide_value;
u32 camera_c_divide_value;
u32 camera_d_divide_value;
} kernelbuf_typedef;
static struct encoder_dev encoder;
/*
* @description : 打开设备
* @param inode : 传递给驱动的inode
* @param - filp : 设备文件file结构体有个叫做private_data的成员变量
* 一般在open的时候将private_data指向设备结构体。
* @return : 0 成功;其他 失败
*/
static int encoder_open(struct inode *inode, struct file *filp)
{
u32 data = readl(encoder_cr_addr);
writel(data | ENCODER_CR_CLR_MASK, encoder_cr_addr);
return 0;
}
/*
* @description : 向设备写数据
* @param - filp : 设备文件,表示打开的文件描述符
* @param - buf : 要写给设备写入的数据
* @param - cnt : 要写入的数据长度
* @param - offt : 相对于文件首地址的偏移
* @return : 写入的字节数,如果为负值,表示写入失败
*/
static ssize_t encoder_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
int ret;
u32 data;
kernelbuf_typedef kern_buf = {
.valve_divide_value = 0,writel
.camera_a_divide_value = 0,
.camera_b_divide_value = 0,
.camera_c_divide_value = 0,
.camera_d_divide_value = 0,
};
if (cnt != sizeof(kern_buf))
{
printk(KERN_ERR "encoder write: cnt error, cnt=%d", cnt);
return -EFAULT;
}
ret = copy_from_user(&kern_buf, buf, cnt); // 得到应用层传递过来的数据
if (ret < 0)
{
printk(KERN_ERR "kernel write failed!\r\n");
return -EFAULT;
}
// 最小分频值为2
if (kern_buf.valve_divide_value < 2 || kern_buf.camera_a_divide_value < 2 ||
kern_buf.camera_b_divide_value < 2 || kern_buf.camera_c_divide_value < 2 ||
kern_buf.camera_d_divide_value < 2)
return -EFAULT;
// 写入0后清除ENCODER内部计数器缓存清除
data = readl(encoder_cr_addr);
writel(data & ~ENCODER_CR_CLR_MASK, encoder_cr_addr);
writel(kern_buf.valve_divide_value, encoder_vdivr_addr);
writel(kern_buf.camera_a_divide_value, encoder_cdivra_addr);
writel(kern_buf.camera_b_divide_value, encoder_cdivrb_addr);
writel(kern_buf.camera_c_divide_value, encoder_cdivrc_addr);
writel(kern_buf.camera_d_divide_value, encoder_cdivrd_addr);
// 写入1退出清除状态使得ENCODER内部计数器能正常工作内部计数器在正常工作前已经被清零
writel(data | ENCODER_CR_CLR_MASK, encoder_cr_addr);
return cnt;
}
/*
* @description : 关闭/释放设备
* @param filp : 要关闭的设备文件(文件描述符)
* @return : 0 成功;其他 失败
*/
static int encoder_release(struct inode *inode, struct file *filp)
{
u32 data = readl(encoder_cr_addr);
writel(data & ~ENCODER_CR_CLR_MASK, encoder_cr_addr);
return 0;
}
static long encoder_ioctl(struct file *fp, unsigned int cmd, unsigned long tmp)
{
u32 data, cmd_parsed;
if (_IOC_TYPE(cmd) != 'D' || _IOC_DIR(cmd) != _IOC_WRITE)
{
printk(KERN_ERR "IOC_TYPE or IOC_WRITE error: IOC_TYPE=%c, IOC_WRITE=%d\r\n", _IOC_TYPE(cmd), _IOC_DIR(cmd));
return -EINVAL;
}
cmd_parsed = _IOC_NR(cmd);
data = readl(encoder_cr_addr);
if (cmd_parsed == ENCODER_CMD_FUNCTION_CLEAR)
{
writel(data & ~ENCODER_CR_CLR_MASK, encoder_cr_addr); // 写入0后清除ENCODER内部计数器缓存清除
writel(data | ENCODER_CR_CLR_MASK, encoder_cr_addr); // 写入1退出清除状态使得ENCODER内部计数器能正常工作内部计数器在正常工作前已经被清零
}
else if (cmd_parsed == ENCODER_CMD_INPUT_MODE_EXTERNEL)
{
// 设为外部触发模式
writel(data & ~ENCODER_CR_MOD_MASK, encoder_cr_addr);
}
else if (cmd_parsed == ENCODER_CMD_INPUT_MODE_INTERNEL)
{
// 设为内部触发模式
writel(data | ENCODER_CR_MOD_MASK, encoder_cr_addr);
}
else if (cmd_parsed == ENCODER_CMD_FUNCTION_VIRT_INPUT)
{
int i;
// 虚拟触发tmp为周期数
// 1. 设为内部触发模式
writel(data | ENCODER_CR_MOD_MASK, encoder_cr_addr);
// 2. 产生虚拟的高低电平
for (i = 0; i < tmp; i++)
{
writel(data & ~ENCODER_CR_VTS_MASK, encoder_cr_addr);
writel(data | ENCODER_CR_VTS_MASK, encoder_cr_addr);
}
// 3. 恢复为原来的状态和模式
writel(data, encoder_cr_addr);
}
else if (cmd_parsed == ENCODER_CMD_CLEAR_MODE_BOTH)
{
// 设为允许内部和外部信号清除缓存
writel(data & ~ENCODER_CR_ICO_MASK, encoder_cr_addr);
}
else if (cmd_parsed == ENCODER_CMD_CLEAR_MODE_INTERNAL)
{
// 设为仅允许内部清除缓存
writel(data | ENCODER_CR_ICO_MASK, encoder_cr_addr);
}
return 0;
}
// 设备操作函数
static struct file_operations encoder_fops = {
.owner = THIS_MODULE,
.open = encoder_open,
.write = encoder_write,
.release = encoder_release,
.unlocked_ioctl = encoder_ioctl,
};
static int __init encoder_init(void)
{
int ret;
u32 data;
// 寄存器地址映射
encoder_cr_addr = ioremap(ENCODER_REG_BASE + ENCODER_REG_0_OFFSET, 4);
encoder_vdivr_addr = ioremap(ENCODER_REG_BASE + ENCODER_REG_1_OFFSET, 4);
encoder_cdivra_addr = ioremap(ENCODER_REG_BASE + ENCODER_REG_2_OFFSET, 4);
encoder_cdivrb_addr = ioremap(ENCODER_REG_BASE + ENCODER_REG_3_OFFSET, 4);
encoder_cdivrc_addr = ioremap(ENCODER_REG_BASE + ENCODER_REG_4_OFFSET, 4);
encoder_cdivrd_addr = ioremap(ENCODER_REG_BASE + ENCODER_REG_5_OFFSET, 4);
// 创建设备号
if (encoder.major)
{
encoder.devid = MKDEV(encoder.major, 0);
ret = register_chrdev_region(encoder.devid, ENCODER_CNT, ENCODER_NAME);
if (ret)
goto FAIL_REGISTER_CHR_DEV;
}
else
{
ret = alloc_chrdev_region(&encoder.devid, 0, ENCODER_CNT, ENCODER_NAME);
if (ret)
goto FAIL_REGISTER_CHR_DEV;
encoder.major = MAJOR(encoder.devid);
encoder.minor = MINOR(encoder.devid);
}
// 初始化cdev
encoder.cdev.owner = THIS_MODULE;
cdev_init(&encoder.cdev, &encoder_fops);
// 添加cdev
ret = cdev_add(&encoder.cdev, encoder.devid, ENCODER_CNT);
if (ret)
goto FAIL_ADD_CDEV;
// 创建类
encoder.class = class_create(THIS_MODULE, ENCODER_NAME);
if (IS_ERR(encoder.class))
{
ret = PTR_ERR(encoder.class);
goto FAIL_CREATE_CLASS;
}
// 创建设备
encoder.device = device_create(encoder.class, NULL, encoder.devid, NULL, ENCODER_NAME);
if (IS_ERR(encoder.device))
{
ret = PTR_ERR(encoder.device);
goto FAIL_CREATE_DEV;
}
// 默认分频系数1000
data = readl(encoder_cr_addr);
writel(data & ~ENCODER_CR_CLR_MASK, encoder_cr_addr); // 清除硬件计数器缓存
writel(1000, encoder_vdivr_addr); // 设置阀触发分频
writel(1000, encoder_cdivra_addr); // 设置相机a触发分频
writel(1000, encoder_cdivrb_addr); // 设置相机b触发分频
writel(1000, encoder_cdivrc_addr); // 设置相机c触发分频
writel(1000, encoder_cdivrd_addr); // 设置相机d触发分频
writel(data | ENCODER_CR_CLR_MASK, encoder_cr_addr); // 清除完毕
return 0;
FAIL_CREATE_DEV:
class_destroy(encoder.class);
FAIL_CREATE_CLASS:
cdev_del(&encoder.cdev);
FAIL_ADD_CDEV:
unregister_chrdev_region(encoder.devid, ENCODER_CNT);
FAIL_REGISTER_CHR_DEV:
iounmap(encoder_cr_addr);
iounmap(encoder_vdivr_addr);
iounmap(encoder_cdivra_addr);
iounmap(encoder_cdivrb_addr);
iounmap(encoder_cdivrc_addr);
iounmap(encoder_cdivrd_addr);
return ret;
}
static void __exit encoder_exit(void)
{
// 注销设备
device_destroy(encoder.class, encoder.devid);
// 注销类
class_destroy(encoder.class);
// 删除cdev
cdev_del(&encoder.cdev);
// 注销设备号
unregister_chrdev_region(encoder.devid, ENCODER_CNT);
// 取消内存映射
iounmap(encoder_cr_addr);
iounmap(encoder_vdivr_addr);
iounmap(encoder_cdivra_addr);
iounmap(encoder_cdivrb_addr);
iounmap(encoder_cdivrc_addr);
iounmap(encoder_cdivrd_addr);
}
module_init(encoder_init);
module_exit(encoder_exit);
MODULE_AUTHOR("DingKun");
MODULE_DESCRIPTION("driver for hardware encoder in the platform");
MODULE_LICENSE("GPL");