来自zynq_book_v2 pwm_driver.c
#include
#include
#include
#include
#include
#define DEVICE_NAME "PWM_MOUDLE"
#define PWM_MOUDLE_PHY_ADDR 0x43C00000 //This Address is based XPS
MODULE_AUTHOR("Xilinx XUP");
MODULE_DESCRIPTION("PWM moudle dirver");
MODULE_VERSION("v1.0");
MODULE_LICENSE("GPL");
static int pwm_driver_major;
static struct class* pwm_driver_class = NULL;
static struct device* pwm_driver_device = NULL;
unsigned long pwm_fre_addr = 0; //pwm moulde's frequency visual address
unsigned long pwm_duty_addr = 0; //pwm moulde's duty visual address
static long frequency=0;
static struct file_operations pwm_driver_fops = {
.owner = THIS_MODULE,
};
static ssize_t sys_pwm_frequency_set (struct device* dev, struct device_attribute* attr, const char* buf, size_t count)
{
long value = 0;
int i;
frequency=0;
iowrite32(value, pwm_fre_addr); //close pwm moudle before we modfiy the frequency
for (i = 0; i < count-1; i++){
frequency *= 10;
frequency += buf[i] - '0';
}
if(value>100000000) value=100000000;
value=100000000/frequency; // 100Mhz/frequency 100Mhz is set by XPS
iowrite32(value, pwm_fre_addr);
return count;
}
static ssize_t sys_pwm_duty_set (struct device* dev, struct device_attribute* attr, const char* buf, size_t count) //duty cycle
{
long value = 0;
int i;
iowrite32(value, pwm_duty_addr); //close pwm moudle before we modfiy the duty cycle
for (i = 0; i < count-1; i++){
value *= 10;
value += buf[i] - '0';
}
if (value>100)
value=100;
value = frequency * value / 100;
if (value!= 0)
value = value | 0x80000000;
printk("duty:%ld\n", value);
iowrite32(value, pwm_duty_addr);
return count;
}
static DEVICE_ATTR(pwm_frequency, S_IWUSR, NULL, sys_pwm_frequency_set);
static DEVICE_ATTR(pwm_duty, S_IWUSR, NULL, sys_pwm_duty_set);
static int __init pwm_driver_module_init(void)
{
int ret;
//此处产生的pwm_driver_major后面device_create函数会用到
//向内核注册一个设备,返回值为注册的主设备号
pwm_driver_major=register_chrdev(0, DEVICE_NAME, &pwm_driver_fops);
if (pwm_driver_major < 0){
printk("failed to register device.\n");
return -1;
}
//注册一个类,使mdev可以在"/dev/"目录下 面建立设备节点
//一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面
pwm_driver_class = class_create(THIS_MODULE, "pwm_driver");
if (IS_ERR(pwm_driver_class)){
printk("failed to create pwm moudle class.\n");
unregister_chrdev(pwm_driver_major, DEVICE_NAME);
return -1;
}
//创建一个设备节点,节点名为DEVICE_NAME
//如果成功,它将会在/dev目录下产生/dev/pwm_device设备。
//
//调用device_create(…)函数来在/dev目录下创建相应的设备节点
//加载模块的时候,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。
/**
* device_create - creates a device and registers it with sysfs
the struct class 指针,必须在本函数调用之前先被创建
* @class: pointer to the struct class that this device should be registered to
* @parent: pointer to the parent struct device of this new device, if any该设备的parent指针。
* @devt: the dev_t for the char device to be added字符设备的设备号,如果dev_t不是0,0的话,1个”dev”文件将被创建。
* @drvdata: the data to be added to the device for callbacks被添加到该设备回调的数据
* @fmt: string for the device's name 设备名字
*/
pwm_driver_device =
device_create(pwm_driver_class, NULL, MKDEV(pwm_driver_major, 0), NULL, "pwm_device");
if (IS_ERR(pwm_driver_device)){
printk("failed to create device .\n");
unregister_chrdev(pwm_driver_major, DEVICE_NAME);
return -1;
}
//利用device_create_file函数可以在/sys/class/下创建对应的属性文件,从而通过对该文件的读写实现特定的数据操作。
//使用这个函数时要引用 device_create所返回的device*指针
ret =
device_create_file(pwm_driver_device, &dev_attr_pwm_frequency);
if (ret < 0)
printk("failed to create pwm_frequency endpoint\n");
ret =
device_create_file(pwm_driver_device, &dev_attr_pwm_duty);
if (ret < 0)
printk("failed to create pwm_duty endpoint\n");
//将FPGA里某东东的物理地址映射到系统虚拟地址(用户)来操作
pwm_fre_addr = (unsigned long)
ioremap(PWM_MOUDLE_PHY_ADDR, 16);//To get Custom IP--PWM moudle's virtual address
printk("basseaddr : %x\r\n", pwm_fre_addr);
pwm_duty_addr = pwm_fre_addr + 4;
printk(" pwm driver initial successfully!\n");
return 0;
}
static void __exit pwm_driver_module_exit(void)
{
printk("exit module.\n");
device_remove_file(pwm_driver_device, &dev_attr_pwm_frequency);
device_remove_file(pwm_driver_device, &dev_attr_pwm_duty);
device_destroy(pwm_driver_class, MKDEV(pwm_driver_major, 0));
class_unregister(pwm_driver_class);
class_destroy(pwm_driver_class);
unregister_chrdev(pwm_driver_major, DEVICE_NAME);
printk("pwm module exit.\n");
}
module_init(pwm_driver_module_init);
module_exit(pwm_driver_module_exit);
阅读(8779) | 评论(2) | 转发(1) |