update
This commit is contained in:
parent
4082b4f8d1
commit
107602167c
@ -1,22 +0,0 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
unsigned int keyval;
|
||||
int fd = 0;
|
||||
/* 打开驱动文件 */
|
||||
fd = open(argv[1], O_RDWR);
|
||||
if (fd<0) printf("can't open %s file\n",argv[1]);
|
||||
|
||||
while(1)
|
||||
{
|
||||
read(fd, &keyval,sizeof(keyval));
|
||||
printf("key_value = %d\n",keyval);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int fd;
|
||||
char* filename=NULL;
|
||||
int val;
|
||||
filename = argv[1];
|
||||
fd = open(filename, O_RDWR);//打开dev/设备文件
|
||||
if (fd < 0)//小于0说明没有成功
|
||||
{
|
||||
printf("error, can't open %s\n", filename);
|
||||
return 0;
|
||||
}
|
||||
if(argc !=3)
|
||||
{
|
||||
printf(argv[1]);//打印用法
|
||||
}
|
||||
if(!strcmp(argv[2], "on")) //如果输入等于on,则LED亮
|
||||
val = 0;
|
||||
else if(!strcmp(argv[2], "off")) //如果输入等于off,则LED灭
|
||||
val = 1;
|
||||
else
|
||||
goto error;
|
||||
write(fd, &val, 4);//操作LED
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
error:
|
||||
printf("usage: ./led_dev.exe [device] [on/off]\n");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/input.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define CHECK_POINT
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int fd = open(argv[1],O_RDONLY);
|
||||
#ifdef CHECK_POINT
|
||||
printf("fd = %d\n",fd);
|
||||
#endif
|
||||
struct input_event t;
|
||||
printf("size of t = %d\n",sizeof(t));
|
||||
while(1)
|
||||
{
|
||||
printf("while -\n");
|
||||
int len = read(fd, &t, sizeof(t));
|
||||
if(len == sizeof(t))
|
||||
{
|
||||
printf("read over\n");
|
||||
if(t.type==EV_KEY)
|
||||
{
|
||||
printf("key %d %s\n", t.code, (t.value) ? "Pressed" : "Released");
|
||||
if(t.code == KEY_ESC)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef CHECK_POINT
|
||||
printf("len = %d\n",len);
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
KERN_DIR = /home/lsw/licheepi/linux-5.7.1
|
||||
|
||||
all:
|
||||
make -C $(KERN_DIR) M=$(shell pwd) modules
|
||||
|
||||
clean:
|
||||
make -C $(KERN_DIR) M=$(shell pwd) modules clean
|
||||
rm -rf modules.order *.ko
|
||||
|
||||
obj-m += at24c02.o
|
||||
|
||||
@ -1,106 +0,0 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/io.h> //含有ioremap函数iounmap函数
|
||||
#include <asm/uaccess.h> //含有copy_from_user函数和含有copy_to_user函数
|
||||
#include <linux/device.h> //含有类相关的设备函数
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/platform_device.h> //包含platform函数
|
||||
#include <linux/of.h> //包含设备树相关函数
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kobject.h> //包含sysfs文件系统对象类
|
||||
#include <linux/sysfs.h> //包含sysfs操作文件函数
|
||||
|
||||
|
||||
static char recv[16] = {0}; //保存接收数据
|
||||
|
||||
static struct kobject *at24c02_kobj; //定义一个led_kobj
|
||||
|
||||
struct i2c_client *at24c02_dev; //定义一个i2c设备结构体指针
|
||||
|
||||
|
||||
static ssize_t at24c02_show(struct kobject* kobjs,struct kobj_attribute *attr,char *buf)
|
||||
{
|
||||
int ret;
|
||||
ret = i2c_smbus_write_byte(at24c02_dev,0x02); //先发写地址操作
|
||||
if(ret)
|
||||
{
|
||||
printk(KERN_ERR"write addr failed!\n");
|
||||
return ret;
|
||||
}
|
||||
recv[0] = i2c_smbus_read_byte(at24c02_dev); //然后发读数据操作
|
||||
return sprintf(buf,"read status register=0x%x\n",recv[0]);
|
||||
}
|
||||
|
||||
static ssize_t at24c02_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
char data = 0x2f;
|
||||
ret = i2c_smbus_write_i2c_block_data(at24c02_dev,0x02,1,&data);//写一个字节数据
|
||||
if(!ret)
|
||||
{
|
||||
printk(KERN_ERR"write data failed!\n");
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct kobj_attribute at24c02_attr = __ATTR(at24c02_dev,0660,at24c02_show,at24c02_store);
|
||||
|
||||
static int at24c02_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
at24c02_kobj = kobject_create_and_add("sys_at24c02",NULL);
|
||||
if(at24c02_kobj == NULL)
|
||||
{
|
||||
printk(KERN_INFO"create at24c02_kobj failed!\n");
|
||||
return -1;
|
||||
}
|
||||
ret = sysfs_create_file(at24c02_kobj, &at24c02_attr.attr);
|
||||
if(ret != 0)
|
||||
{
|
||||
printk(KERN_INFO"create at24c02_dev file failed!\n");
|
||||
return -1;
|
||||
}
|
||||
at24c02_dev = client; //初始化i2c设备结构体指针
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at24c02_remove(struct i2c_client *client)
|
||||
{
|
||||
sysfs_remove_file(at24c02_kobj, &at24c02_attr.attr); //删除属性
|
||||
kobject_put(at24c02_kobj); //删除对象
|
||||
printk(KERN_INFO "exit sysfs at24c02!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id at24c02_id[] = {
|
||||
{ "test,at24c0x", 0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct of_device_id at24c02_of_match[] = {
|
||||
{ .compatible = "test,at24c0x"},
|
||||
{ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, at24c02_of_match);
|
||||
|
||||
static struct i2c_driver at24c02_driver = {
|
||||
.driver = {
|
||||
.name = "test,at24c0x",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = at24c02_of_match,
|
||||
},
|
||||
.probe = at24c02_probe,
|
||||
.remove = at24c02_remove,
|
||||
.id_table = at24c02_id,
|
||||
};
|
||||
|
||||
|
||||
module_i2c_driver(at24c02_driver);
|
||||
|
||||
MODULE_LICENSE("GPL"); //不加的话加载会有错误提醒
|
||||
MODULE_AUTHOR("1477153217@qq.com"); //作者
|
||||
MODULE_VERSION("0.1"); //版本
|
||||
MODULE_DESCRIPTION("at24c02_driver"); //简单的描述
|
||||
@ -1,11 +0,0 @@
|
||||
KERN_DIR = /home/lsw/licheepi/linux-5.7.1
|
||||
|
||||
all:
|
||||
make -C $(KERN_DIR) M=$(shell pwd) modules
|
||||
|
||||
clean:
|
||||
make -C $(KERN_DIR) M=$(shell pwd) modules clean
|
||||
rm -rf modules.order *.ko
|
||||
|
||||
obj-m += myfb.o
|
||||
|
||||
@ -1,128 +0,0 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/io.h> //含有ioremap函数iounmap函数
|
||||
#include <asm/uaccess.h> //含有copy_from_user函数和含有copy_to_user函数
|
||||
#include <linux/device.h> //含有类相关的设备函数
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/platform_device.h> //包含platform函数
|
||||
#include <linux/of.h> //包含设备树相关函数
|
||||
#include <linux/fb.h> //包含frame buffer
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
struct fb_info *myfb; //定义一个fb_info
|
||||
struct spi_device *myfb_spi; //spi接口
|
||||
|
||||
|
||||
static struct of_device_id myfb_spi_match_table[] = {
|
||||
{.compatible = "test,myfb-spi"},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, myfb_spi_match_table);
|
||||
|
||||
static int myfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
|
||||
{
|
||||
if (var->xres < 0 || var->yres < 0 ||
|
||||
var->xres > 240 || var->yres > 240 ||
|
||||
var->bits_per_pixel != 16)
|
||||
return -EINVAL;
|
||||
|
||||
var->xres_virtual = var->xres;
|
||||
var->yres_virtual = var->yres;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline u32 chan_to_field(u32 chan, struct fb_bitfield *bf)
|
||||
{
|
||||
return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
|
||||
}
|
||||
|
||||
|
||||
static int myfb_setcolreg(unsigned regno, unsigned red, unsigned green,unsigned blue, unsigned transp, struct fb_info *info)
|
||||
{
|
||||
u32 *pal = info->pseudo_palette;
|
||||
|
||||
if (regno > 15)
|
||||
return -EINVAL;
|
||||
|
||||
pal[regno] = chan_to_field(red, &info->var.red)
|
||||
| chan_to_field(green, &info->var.green)
|
||||
| chan_to_field(blue, &info->var.blue)
|
||||
| chan_to_field(transp, &info->var.transp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int myfb_blank(int blank, struct fb_info *info)
|
||||
{
|
||||
return 1; /* get fb_blank to set the colormap to all black */
|
||||
}
|
||||
|
||||
|
||||
struct fb_ops myfb_ops = //定义一个fb_ops结构体指针
|
||||
{
|
||||
.owner = THIS_MODULE,
|
||||
.fb_check_var = myfb_check_var,
|
||||
//.fb_set_par = myfb_set_par;
|
||||
.fb_setcolreg = myfb_setcolreg,
|
||||
.fb_fillrect = cfb_fillrect,
|
||||
.fb_copyarea = cfb_copyarea,
|
||||
.fb_imageblit = cfb_imageblit,
|
||||
.fb_blank = myfb_blank,
|
||||
};
|
||||
|
||||
|
||||
static int myfb_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
int ret;
|
||||
printk(KERN_ERR"register myfb_spi_probe!\n");
|
||||
myfb_spi = spi_dev_get(spi);
|
||||
printk(KERN_ERR"register myfb_probe dev!\n");
|
||||
myfb = framebuffer_alloc(sizeof(struct fb_info), &spi->dev); //向内核申请fb_info结构体
|
||||
//初始化底层操作结构体
|
||||
myfb->fbops = &myfb_ops;
|
||||
|
||||
ret = register_framebuffer(myfb);
|
||||
if(ret)
|
||||
{
|
||||
framebuffer_release(myfb);
|
||||
unregister_framebuffer(myfb);
|
||||
printk(KERN_ERR"fail to register fb dev!\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int myfb_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
framebuffer_release(myfb);
|
||||
unregister_framebuffer(myfb);
|
||||
printk(KERN_INFO "exit myfb!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct spi_driver myfb_spi_driver = {
|
||||
.driver = {
|
||||
.name = "myfb",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = myfb_spi_match_table,
|
||||
},
|
||||
.probe = myfb_spi_probe,
|
||||
.remove = myfb_spi_remove,
|
||||
};
|
||||
|
||||
|
||||
module_spi_driver(myfb_spi_driver);
|
||||
|
||||
|
||||
MODULE_LICENSE("GPL"); //不加的话加载会有错误提醒
|
||||
MODULE_AUTHOR("1477153217@qq.com"); //作者
|
||||
MODULE_VERSION("0.1"); //版本
|
||||
MODULE_DESCRIPTION("myfb_spi_driver"); //简单的描述
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
KERN_DIR = /home/lsw/licheepi/linux-5.7.1
|
||||
|
||||
all:
|
||||
make -C $(KERN_DIR) M=$(shell pwd) modules
|
||||
|
||||
clean:
|
||||
make -C $(KERN_DIR) M=$(shell pwd) modules clean
|
||||
rm -rf modules.order *.ko
|
||||
|
||||
obj-m +=gpio_subsys.o
|
||||
|
||||
@ -1,109 +0,0 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/io.h> //含有ioremap函数iounmap函数
|
||||
#include <asm/uaccess.h> //含有copy_from_user函数和含有copy_to_user函数
|
||||
#include <linux/device.h> //含有类相关的设备函数
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/platform_device.h> //包含platform函数
|
||||
#include <linux/of.h> //包含设备树相关函数
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/kobject.h> //包含sysfs文件系统对象类
|
||||
#include <linux/sysfs.h> //包含sysfs操作文件函数
|
||||
#include <linux/gpio/consumer.h> //包含gpio子系统接口
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/gpio.h> //包含gpio一些宏
|
||||
|
||||
|
||||
static struct kobject *led_kobj; //定义一个led_kobj
|
||||
struct gpio_desc *led_pin; //gpio资源
|
||||
|
||||
static ssize_t led_show(struct kobject* kobjs,struct kobj_attribute *attr,char *buf)
|
||||
{
|
||||
return sprintf(buf,"led status=%d\n",gpiod_get_value(led_pin));
|
||||
}
|
||||
|
||||
static ssize_t led_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t count)
|
||||
{
|
||||
if(0 == memcmp(buf,"on",2))
|
||||
{
|
||||
gpiod_set_value(led_pin,0);
|
||||
}
|
||||
else if(0 == memcmp(buf,"off",3))
|
||||
{
|
||||
gpiod_set_value(led_pin,1);
|
||||
}
|
||||
else
|
||||
{
|
||||
printk(KERN_INFO "Not support cmd\n");
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct kobj_attribute led_attr = __ATTR(led_dev,0660,led_show,led_store);
|
||||
|
||||
|
||||
static int led_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
led_kobj = kobject_create_and_add("sys_led",NULL);
|
||||
if(led_kobj == NULL)
|
||||
{
|
||||
printk(KERN_INFO"create led_kobj failed!\n");
|
||||
return -1;
|
||||
}
|
||||
ret = sysfs_create_file(led_kobj,&led_attr.attr);
|
||||
if(ret != 0)
|
||||
{
|
||||
printk(KERN_INFO"create w25q128_dev file failed!\n");
|
||||
return -1;
|
||||
}
|
||||
led_pin = devm_gpiod_get(&pdev->dev,"led",GPIOF_OUT_INIT_LOW);
|
||||
if(IS_ERR(led_pin))
|
||||
{
|
||||
printk(KERN_ERR"Get gpio resource failed!\n");
|
||||
return -1;
|
||||
}
|
||||
gpiod_direction_output(led_pin,0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int led_remove(struct platform_device *pdev)
|
||||
{
|
||||
sysfs_remove_file(led_kobj, &led_attr.attr); //删除属性
|
||||
kobject_put(led_kobj); //删除对象
|
||||
devm_gpiod_put(&pdev->dev,led_pin);
|
||||
printk(KERN_INFO "exit sysfs sys_led!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct of_device_id led_match_table[] = {
|
||||
{.compatible = "test,led_subsys",},
|
||||
};
|
||||
|
||||
static struct platform_device_id led_ids[] = {
|
||||
{.name = "led_subsys",},
|
||||
};
|
||||
|
||||
static struct platform_driver led_cdev = {
|
||||
.driver = {
|
||||
.name = "led_subsys",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = led_match_table,
|
||||
},
|
||||
.probe = led_probe,
|
||||
.remove = led_remove,
|
||||
.id_table = led_ids,
|
||||
};
|
||||
|
||||
|
||||
module_platform_driver(led_cdev);
|
||||
|
||||
MODULE_LICENSE("GPL"); //不加的话加载会有错误提醒
|
||||
MODULE_AUTHOR("1477153217@qq.com"); //作者
|
||||
MODULE_VERSION("0.1"); //版本
|
||||
MODULE_DESCRIPTION("led_cdev"); //简单的描述
|
||||
@ -1,11 +0,0 @@
|
||||
KERN_DIR = /home/lsw/licheepi/linux-5.7.1
|
||||
|
||||
all:
|
||||
make -C $(KERN_DIR) M=$(shell pwd) modules
|
||||
|
||||
clean:
|
||||
make -C $(KERN_DIR) M=$(shell pwd) modules clean
|
||||
rm -rf modules.order *.ko
|
||||
|
||||
obj-m +=key_dev_platform.o
|
||||
|
||||
@ -1,150 +0,0 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/io.h> //含有iomap函数iounmap函数
|
||||
#include <asm/uaccess.h> //含有copy_from_user函数
|
||||
#include <linux/device.h> //含有类相关的处理函数
|
||||
#include <linux/irq.h> //含有IRQ_HANDLED和IRQ_TYPE_EDGE_RISING
|
||||
#include <linux/interrupt.h> //含有request_irq、free_irq函数
|
||||
#include <linux/cdev.h>
|
||||
|
||||
|
||||
|
||||
static dev_t btn_cdev_num; //定义一个设备号
|
||||
static struct cdev *btn_cdev; //定义一个设备管理结构体指针
|
||||
static struct class *btn_class; //定义一个设备类
|
||||
static struct device *btn; //定义一个设备
|
||||
|
||||
#define KEYADC_BASE (0x01C22800)
|
||||
#define KEYADC_CTRL_REG (KEYADC_BASE+0x00)
|
||||
#define KEYADC_INTC_REG (KEYADC_BASE+0x04)
|
||||
#define KEYADC_INTS_REG (KEYADC_BASE+0x08)
|
||||
#define KEYADC_DATA_REG (KEYADC_BASE+0x0C)
|
||||
|
||||
ssize_t volatile *keyadc_ctrl;
|
||||
ssize_t volatile *keyadc_intc;
|
||||
ssize_t volatile *keyadc_ints;
|
||||
ssize_t volatile *keyadc_data;
|
||||
|
||||
|
||||
static unsigned int ev_press; //一个全局变量,记录中断事件状态
|
||||
DECLARE_WAIT_QUEUE_HEAD(btn_waitq);//注册一个等待队列button_waitq,用宏来申明一个全局变量
|
||||
static unsigned int key_value = 0; //定义一个变量保存按键值
|
||||
|
||||
static irqreturn_t btn_irq(int irq, void *dev_id)
|
||||
{
|
||||
wake_up_interruptible(&btn_waitq); /* 唤醒休眠的进程,即调用read函数的进程 */
|
||||
ev_press = 1;
|
||||
*keyadc_ints |= ((1<<0)|(1<<1) | (1<<2) |(1<<3)|(1<<4));
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int btn_cdev_open (struct inode * inode, struct file * file)
|
||||
{
|
||||
*keyadc_intc |= ((1<<0)|(1<<1)|(1<<4));
|
||||
*keyadc_ctrl |= (1<<7);
|
||||
*keyadc_ctrl &= ~(0xf<<8);
|
||||
*keyadc_ctrl |= (1<<0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btn_cdev_close(struct inode * inode, struct file * file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t btn_cdev_read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
|
||||
{
|
||||
int ret;
|
||||
unsigned int adc_value;
|
||||
adc_value = *(keyadc_data);
|
||||
//将当前进程放入等待队列button_waitq中,并且释放CPU进入睡眠状态
|
||||
wait_event_interruptible(btn_waitq, ev_press!=0);
|
||||
ret = copy_to_user(userbuf, &adc_value, 4);//将取得的按键值传给上层应用
|
||||
|
||||
printk(KERN_WARNING"key adc = %d\n",(adc_value&(0x3f)));
|
||||
printk(KERN_WARNING"key statue = 0x%x\n",*(keyadc_ints));
|
||||
ev_press = 0;//按键已经处理可以继续睡眠
|
||||
if(ret)
|
||||
{
|
||||
printk("copy error\n");
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct file_operations btn_cdev_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = btn_cdev_open,
|
||||
.read = btn_cdev_read,
|
||||
.release = btn_cdev_close,
|
||||
};
|
||||
|
||||
|
||||
static int btn_cdev_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
btn_cdev = cdev_alloc(); //动态申请一个设备结构体
|
||||
if(btn_cdev == NULL)
|
||||
{
|
||||
printk(KERN_WARNING"cdev_alloc failed!\n");
|
||||
return -1;
|
||||
}
|
||||
ret = alloc_chrdev_region(&btn_cdev_num,0,1,"button"); //动态申请一个设备号
|
||||
if(ret !=0)
|
||||
{
|
||||
printk(KERN_WARNING"alloc_chrdev_region failed!\n");
|
||||
return -1;
|
||||
}
|
||||
btn_cdev->owner = THIS_MODULE; //初始化设备管理结构体的owner为THIS_MODULE
|
||||
btn_cdev->ops = &btn_cdev_ops; //初始化设备操作函数指针为led_ops函数
|
||||
cdev_add(btn_cdev,btn_cdev_num,1); //将设备添加到内核中
|
||||
btn_class = class_create(THIS_MODULE, "button"); //创建一个名为led_class的类
|
||||
if(btn_class == NULL)
|
||||
{
|
||||
printk(KERN_WARNING"btn_class failed!\n");
|
||||
return -1;
|
||||
}
|
||||
btn = device_create(btn_class,NULL,btn_cdev_num,NULL,"button0"); //创建一个设备名为led0
|
||||
if(IS_ERR(btn))
|
||||
{
|
||||
printk(KERN_WARNING"device_create failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
keyadc_ctrl = ioremap(KEYADC_CTRL_REG, 4);//重映射
|
||||
keyadc_intc = ioremap(KEYADC_INTC_REG, 4);//重映射
|
||||
keyadc_ints = ioremap(KEYADC_INTS_REG, 4);//重映射
|
||||
keyadc_data = ioremap(KEYADC_DATA_REG, 4);//重映射
|
||||
ret = request_any_context_irq(35, btn_irq, 0 , "btn",(void*)&key_value);
|
||||
if(ret) //返回不为0,表示申请失败
|
||||
{
|
||||
printk("request irq failed!\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void btn_cdev_exit(void)
|
||||
{
|
||||
cdev_del(btn_cdev); //从内核中删除设备管理结构体
|
||||
unregister_chrdev_region(btn_cdev_num,1); //注销设备号
|
||||
device_destroy(btn_class,btn_cdev_num); //删除设备节点
|
||||
class_destroy(btn_class); //删除设备类
|
||||
|
||||
iounmap(keyadc_ctrl);//取消重映射
|
||||
iounmap(keyadc_intc);//取消重映射
|
||||
iounmap(keyadc_ints);//取消重映射
|
||||
iounmap(keyadc_data);//取消重映射
|
||||
free_irq(35,(void*)&key_value);//释放中断
|
||||
printk("unregister btn_cdev\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
module_init(btn_cdev_init);
|
||||
module_exit(btn_cdev_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
@ -1,174 +0,0 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/io.h> //含有ioremap函数iounmap函数
|
||||
#include <asm/uaccess.h> //含有copy_from_user函数和含有copy_to_user函数
|
||||
#include <linux/device.h> //含有类相关的设备函数
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/platform_device.h> //包含platform函数
|
||||
#include <linux/of.h> //包含设备树相关函数
|
||||
#include <linux/irq.h> //含有IRQ_HANDLED和IRQ_TYPE_EDGE_RISING
|
||||
#include <linux/interrupt.h> //含有request_irq、free_irq函数
|
||||
|
||||
|
||||
|
||||
static dev_t btn_cdev_num; //定义一个设备号
|
||||
static struct cdev *btn_cdev; //定义一个设备管理结构体指针
|
||||
static struct class *btn_class; //定义一个设备类
|
||||
static struct device *btn; //定义一个设备
|
||||
|
||||
ssize_t volatile *keyadc_ctrl;
|
||||
ssize_t volatile *keyadc_intc;
|
||||
ssize_t volatile *keyadc_ints;
|
||||
ssize_t volatile *keyadc_data;
|
||||
|
||||
static unsigned int ev_press; //一个全局变量,记录中断事件状态
|
||||
DECLARE_WAIT_QUEUE_HEAD(btn_waitq);//注册一个等待队列button_waitq,用宏来申明一个全局变量
|
||||
static unsigned int key_value = 0; //定义一个变量保存按键值
|
||||
|
||||
|
||||
static irqreturn_t btn_irq(int irq, void *dev_id)
|
||||
{
|
||||
ssize_t ints_clr = *keyadc_ints;
|
||||
ints_clr = *keyadc_ints;
|
||||
wake_up_interruptible(&btn_waitq); /* 唤醒休眠的进程,即调用read函数的进程 */
|
||||
ev_press = 1;
|
||||
*keyadc_ints |= ints_clr;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int btn_cdev_open (struct inode * inode, struct file * file)
|
||||
{
|
||||
*keyadc_ctrl&=0;
|
||||
*keyadc_ctrl |= (2<<24) | (1<<8) | (1<<6);
|
||||
*keyadc_intc |= (1<<4) | (1<<1);
|
||||
*keyadc_ctrl |= (1<<0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btn_cdev_close(struct inode * inode, struct file * file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t btn_cdev_read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
|
||||
{
|
||||
int ret;
|
||||
unsigned int adc_value;
|
||||
adc_value = *(keyadc_data);
|
||||
//将当前进程放入等待队列button_waitq中,并且释放CPU进入睡眠状态
|
||||
wait_event_interruptible(btn_waitq, ev_press!=0);
|
||||
ret = copy_to_user(userbuf, &adc_value, 4);//将取得的按键值传给上层应用
|
||||
|
||||
printk(KERN_WARNING"key adc = %d\n",(adc_value&(0x3f)));
|
||||
printk(KERN_WARNING"key statue = 0x%x\n",*(keyadc_ints));
|
||||
ev_press = 0;//按键已经处理可以继续睡眠
|
||||
if(ret)
|
||||
{
|
||||
printk("copy error\n");
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct file_operations btn_cdev_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = btn_cdev_open,
|
||||
.read = btn_cdev_read,
|
||||
.release = btn_cdev_close,
|
||||
};
|
||||
|
||||
|
||||
static int btn_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
||||
|
||||
int ret;
|
||||
struct resource *res;
|
||||
|
||||
btn_cdev = cdev_alloc(); //动态申请一个设备结构体
|
||||
if(btn_cdev == NULL)
|
||||
{
|
||||
printk(KERN_WARNING"cdev_alloc failed!\n");
|
||||
return -1;
|
||||
}
|
||||
ret = alloc_chrdev_region(&btn_cdev_num,0,1,"button"); //动态申请一个设备号
|
||||
if(ret !=0)
|
||||
{
|
||||
printk(KERN_WARNING"alloc_chrdev_region failed!\n");
|
||||
return -1;
|
||||
}
|
||||
btn_cdev->owner = THIS_MODULE; //初始化设备管理结构体的owner为THIS_MODULE
|
||||
btn_cdev->ops = &btn_cdev_ops; //初始化设备操作函数指针为led_ops函数
|
||||
cdev_add(btn_cdev,btn_cdev_num,1); //将设备添加到内核中
|
||||
btn_class = class_create(THIS_MODULE, "button"); //创建一个名为led_class的类
|
||||
if(btn_class == NULL)
|
||||
{
|
||||
printk(KERN_WARNING"btn_class failed!\n");
|
||||
return -1;
|
||||
}
|
||||
btn = device_create(btn_class,NULL,btn_cdev_num,NULL,"button0"); //创建一个设备名为led0
|
||||
if(IS_ERR(btn))
|
||||
{
|
||||
printk(KERN_WARNING"device_create failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取device中的LRADC_CTRL
|
||||
keyadc_ctrl = ioremap(res->start,(res->end - res->start)+1);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1); //获取device中的LRADC_INTC
|
||||
keyadc_intc = ioremap(res->start,(res->end - res->start)+1);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 2); //获取device中的LRADC_INTS
|
||||
keyadc_ints = ioremap(res->start,(res->end - res->start)+1);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 3); //获取device中的LRADC_DATA
|
||||
keyadc_data = ioremap(res->start,(res->end - res->start)+1);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, platform_get_irq(pdev, 0), btn_irq, 0, "mykey", (void*)&key_value);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btn_remove(struct platform_device *pdev)
|
||||
{
|
||||
iounmap(keyadc_ctrl); //取消LRADC_CTRL映射
|
||||
iounmap(keyadc_intc); //取消LRADC_INTC映射
|
||||
iounmap(keyadc_ints); //取消LRADC_INTS映射
|
||||
iounmap(keyadc_data); //取消LRADC_DATA映射
|
||||
cdev_del(btn_cdev); //从内核中删除设备管理结构体
|
||||
|
||||
unregister_chrdev_region(btn_cdev_num,1); //注销设备号
|
||||
device_destroy(btn_class,btn_cdev_num); //删除设备节点
|
||||
class_destroy(btn_class); //删除设备类
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id btn_match_table[] = {
|
||||
{.compatible = "mykey",},
|
||||
};
|
||||
|
||||
static struct platform_device_id btn_device_ids[] = {
|
||||
{.name = "btn",},
|
||||
};
|
||||
|
||||
static struct platform_driver btn_driver=
|
||||
{
|
||||
.probe = btn_probe,
|
||||
.remove = btn_remove,
|
||||
.driver={
|
||||
.name = "btn",
|
||||
.of_match_table = btn_match_table,
|
||||
},
|
||||
.id_table = btn_device_ids,
|
||||
};
|
||||
|
||||
|
||||
module_platform_driver(btn_driver);
|
||||
|
||||
MODULE_LICENSE("GPL"); //不加的话加载会有错误提醒
|
||||
MODULE_AUTHOR("1477153217@qq.com"); //作者
|
||||
MODULE_VERSION("0.1"); //版本
|
||||
MODULE_DESCRIPTION("btn_driver"); //简单的描述
|
||||
@ -1,11 +0,0 @@
|
||||
KERN_DIR = /home/lsw/licheepi/linux-5.7.1
|
||||
|
||||
all:
|
||||
make -C $(KERN_DIR) M=$(shell pwd) modules
|
||||
|
||||
clean:
|
||||
make -C $(KERN_DIR) M=$(shell pwd) modules clean
|
||||
rm -rf modules.order *.ko
|
||||
|
||||
obj-m +=mykeypad.o
|
||||
|
||||
@ -1,163 +0,0 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/io.h> //含有ioremap函数iounmap函数
|
||||
#include <asm/uaccess.h> //含有copy_from_user函数和含有copy_to_user函数
|
||||
#include <linux/device.h> //含有类相关的设备函数
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/platform_device.h> //包含platform函数
|
||||
#include <linux/of.h> //包含设备树相关函数
|
||||
#include <linux/irq.h> //含有IRQ_HANDLED和IRQ_TYPE_EDGE_RISING
|
||||
#include <linux/interrupt.h> //含有request_irq、free_irq函数
|
||||
#include <linux/input.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
struct input_dev *mykeypad_dev; //定义一个input_dev结构体
|
||||
|
||||
ssize_t volatile *keyadc_ctrl;
|
||||
ssize_t volatile *keyadc_intc;
|
||||
ssize_t volatile *keyadc_ints;
|
||||
ssize_t volatile *keyadc_data;
|
||||
|
||||
static unsigned int key_value = 0; //定义一个变量保存按键值
|
||||
|
||||
static irqreturn_t mykeypad_irq (int irq, void *dev_id) //中断服务函数
|
||||
{
|
||||
ssize_t key_value;
|
||||
/*上报事件*/
|
||||
key_value = ((*keyadc_data)&(0x3f));
|
||||
if(((*keyadc_ints)&(1<<1)) != 0)
|
||||
{
|
||||
if(key_value == 24)
|
||||
{
|
||||
input_event(mykeypad_dev, EV_KEY, KEY_A , 1); //上报EV_KEY类型,button按键,1(按下)
|
||||
}
|
||||
else if(key_value == 17)
|
||||
{
|
||||
input_event(mykeypad_dev, EV_KEY, KEY_B, 1); //上报EV_KEY类型,button按键,1(按下)
|
||||
}
|
||||
else if(key_value == 11)
|
||||
{
|
||||
input_event(mykeypad_dev, EV_KEY, KEY_C, 1); //上报EV_KEY类型,button按键,1(按下)
|
||||
}
|
||||
else
|
||||
{
|
||||
input_event(mykeypad_dev, EV_KEY, KEY_D, 1); //上报EV_KEY类型,button按键,1(按下)
|
||||
}
|
||||
}
|
||||
else if(((*keyadc_ints)&(1<<4)) != 0)
|
||||
{
|
||||
if(key_value == 24)
|
||||
{
|
||||
input_event(mykeypad_dev, EV_KEY, KEY_A , 0); //上报EV_KEY类型,button按键,1(按下)
|
||||
}
|
||||
else if(key_value == 17)
|
||||
{
|
||||
input_event(mykeypad_dev, EV_KEY, KEY_B, 0); //上报EV_KEY类型,button按键,1(按下)
|
||||
}
|
||||
else if(key_value == 11)
|
||||
{
|
||||
input_event(mykeypad_dev, EV_KEY, KEY_C, 0); //上报EV_KEY类型,button按键,1(按下)
|
||||
}
|
||||
else
|
||||
{
|
||||
input_event(mykeypad_dev, EV_KEY, KEY_D, 0); //上报EV_KEY类型,button按键,1(按下)
|
||||
}
|
||||
}
|
||||
|
||||
input_sync(mykeypad_dev); // 上传同步事件,告诉系统有事件出现
|
||||
*keyadc_ints |= ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4));
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int mykeypad_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct resource *res;
|
||||
mykeypad_dev=input_allocate_device(); //向内核申请input_dev结构体
|
||||
set_bit(EV_KEY,mykeypad_dev->evbit); //支持键盘事件
|
||||
set_bit(EV_REP,mykeypad_dev->evbit); //支持键盘重复按事件
|
||||
set_bit(KEY_A,mykeypad_dev->keybit); //支持按键 A
|
||||
set_bit(KEY_B,mykeypad_dev->keybit); //支持按键 B
|
||||
set_bit(KEY_C,mykeypad_dev->keybit); //支持按键 C
|
||||
set_bit(KEY_D,mykeypad_dev->keybit); //支持按键 D
|
||||
|
||||
mykeypad_dev->name = pdev->name; //设备名称
|
||||
mykeypad_dev->phys = "mykeypad/input0"; //设备文件路径
|
||||
mykeypad_dev->open = NULL; //设备打开操作函数
|
||||
mykeypad_dev->close = NULL; //设备关闭操作函数
|
||||
mykeypad_dev->id.bustype = BUS_HOST; //设备总线类型
|
||||
mykeypad_dev->id.vendor = 0x0001; //设备厂家编号
|
||||
mykeypad_dev->id.product = 0x0001; //设备产品编号
|
||||
mykeypad_dev->id.version = 0x0100; //设备版本
|
||||
|
||||
ret = input_register_device(mykeypad_dev); //注册input_dev
|
||||
if(ret)
|
||||
{
|
||||
input_free_device(mykeypad_dev);
|
||||
printk(KERN_ERR "regoster input device failed!\n");
|
||||
return ret;
|
||||
}
|
||||
mykeypad_dev->name="mykeypad";
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取device中的LRADC_CTRL
|
||||
keyadc_ctrl = ioremap(res->start,(res->end - res->start)+1);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1); //获取device中的LRADC_INTC
|
||||
keyadc_intc = ioremap(res->start,(res->end - res->start)+1);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 2); //获取device中的LRADC_INTS
|
||||
keyadc_ints = ioremap(res->start,(res->end - res->start)+1);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 3); //获取device中的LRADC_DATA
|
||||
keyadc_data = ioremap(res->start,(res->end - res->start)+1);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, platform_get_irq(pdev, 0), mykeypad_irq, 0, "mykey", (void*)&key_value);
|
||||
*keyadc_ctrl&=0;
|
||||
*keyadc_ctrl |= (2<<24) | (1<<8) | (1<<6);
|
||||
*keyadc_intc |= (1<<4) | (1<<1);
|
||||
*keyadc_ctrl |= (1<<0);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int mykeypad_remove(struct platform_device *pdev)
|
||||
{
|
||||
iounmap(keyadc_ctrl); //取消LRADC_CTRL映射
|
||||
iounmap(keyadc_intc); //取消LRADC_INTC映射
|
||||
iounmap(keyadc_ints); //取消LRADC_INTS映射
|
||||
iounmap(keyadc_data); //取消LRADC_DATA映射
|
||||
|
||||
input_unregister_device(mykeypad_dev); //卸载类下的驱动设备
|
||||
input_free_device(mykeypad_dev); //释放驱动结构体
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct of_device_id mykeypad_match_table[] = {
|
||||
{.compatible = "mykeypad",},
|
||||
};
|
||||
|
||||
static struct platform_device_id mykeypad_device_ids[] = {
|
||||
{.name = "mykeypad",},
|
||||
};
|
||||
|
||||
static struct platform_driver mykeypad_driver=
|
||||
{
|
||||
.probe = mykeypad_probe,
|
||||
.remove = mykeypad_remove,
|
||||
.driver={
|
||||
.name = "mykeypad",
|
||||
.of_match_table = mykeypad_match_table,
|
||||
},
|
||||
.id_table = mykeypad_device_ids,
|
||||
};
|
||||
|
||||
|
||||
module_platform_driver(mykeypad_driver);
|
||||
|
||||
MODULE_LICENSE("GPL"); //不加的话加载会有错误提醒
|
||||
MODULE_AUTHOR("1477153217@qq.com"); //作者
|
||||
MODULE_VERSION("0.1"); //版本
|
||||
MODULE_DESCRIPTION("mykeypad_driver"); //简单的描述
|
||||
@ -1,11 +0,0 @@
|
||||
KERN_DIR = /home/lsw/licheepi/linux-5.7.1
|
||||
|
||||
all:
|
||||
make -C $(KERN_DIR) M=$(shell pwd) modules
|
||||
|
||||
clean:
|
||||
make -C $(KERN_DIR) M=$(shell pwd) modules clean
|
||||
rm -rf modules.order *.ko
|
||||
|
||||
obj-m +=sysfs_led_dev.o
|
||||
|
||||
@ -1,141 +0,0 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/io.h> //含有ioremap函数iounmap函数
|
||||
#include <asm/uaccess.h> //含有copy_from_user函数和含有copy_to_user函数
|
||||
#include <linux/device.h> //含有类相关的设备函数
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/platform_device.h> //包含platform函数
|
||||
#include <linux/of.h> //包含设备树相关函数
|
||||
#include <linux/miscdevice.h> //包含misc相关函数
|
||||
|
||||
size_t *gpioe_cfg0; //存储虚拟地址到物理地址映射
|
||||
size_t *gpioe_cfg1; //存储虚拟地址到物理地址映射
|
||||
size_t *gpioe_data; //存储虚拟地址到物理地址映射
|
||||
size_t *gpioe_pul0; //存储虚拟地址到物理地址映射
|
||||
|
||||
static int misc_led_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
/* GPIOE配置 */
|
||||
*((volatile size_t*)gpioe_cfg1) &= ~(7<<16); //清除配置寄存器
|
||||
*((volatile size_t*)gpioe_cfg1) |= (1<<16); //配置GPIOE12为输出模式
|
||||
*((volatile size_t*)gpioe_pul0) &= ~(3<<16); //清除上/下拉寄存器
|
||||
*((volatile size_t*)gpioe_pul0) |= (1<<12); //配置GPIOE12为上拉模式
|
||||
printk(KERN_DEBUG"open led!!!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int misc_led_close(struct inode *inode, struct file *filp)
|
||||
{
|
||||
/* GPIOE配置 */
|
||||
printk(KERN_DEBUG"close led!!!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int misc_led_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
|
||||
{
|
||||
int ret;
|
||||
size_t status = *((volatile size_t*)gpioe_data);//获取GPIOE12状态
|
||||
ret = copy_to_user(buff,&status,4); //将内核空间拷贝到用户空间buff
|
||||
if(ret < 0)
|
||||
printk(KERN_DEBUG"read error!!!\n"); //输出信息
|
||||
else
|
||||
printk(KERN_DEBUG"read led ok!!!\n"); //输出信息
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int misc_led_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
|
||||
{
|
||||
int ret;
|
||||
size_t status;
|
||||
ret = copy_from_user(&status,buff,4); //将用户空间拷贝到内核空间的status
|
||||
if(ret < 0)
|
||||
printk(KERN_DEBUG"write error!!!\n"); //输出信息
|
||||
else
|
||||
printk(KERN_DEBUG"write led ok!!!\n"); //输出信息
|
||||
*((volatile size_t*)gpioe_data) &= ~(1<<12) ;//清除GPIOE12状态
|
||||
if(status)
|
||||
*((volatile size_t*)gpioe_data) |= (1<<12);//设置GPIOE12状态1
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations misc_led_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = misc_led_open,
|
||||
.read = misc_led_read,
|
||||
.write = misc_led_write,
|
||||
.release = misc_led_close,
|
||||
};
|
||||
|
||||
|
||||
static struct miscdevice misc_led_dev = {
|
||||
.minor = MISC_DYNAMIC_MINOR, //动态分配次设备号
|
||||
.name = "miscled",
|
||||
.fops = &misc_led_ops, //文件操作集
|
||||
};
|
||||
|
||||
static int misc_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
misc_register(&misc_led_dev); //注册misc设备
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取device中的GPIOE_CFG0
|
||||
gpioe_cfg0 = ioremap(res->start,(res->end - res->start)+1);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1); //获取device中的GPIOE_CFG1
|
||||
gpioe_cfg1 = ioremap(res->start,(res->end - res->start)+1);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 2); //获取device中的GPIOE_DATA
|
||||
gpioe_data = ioremap(res->start,(res->end - res->start)+1);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 3); //获取device中的GPIOE_PUL0
|
||||
gpioe_pul0 = ioremap(res->start,(res->end - res->start)+1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int misc_led_remove(struct platform_device *pdev)
|
||||
{
|
||||
iounmap(gpioe_cfg0); //取消GPIOE_CFG0映射
|
||||
iounmap(gpioe_cfg1); //取消GPIOE_CFG1映射
|
||||
iounmap(gpioe_data); //取消GPIOE_DATA映射
|
||||
iounmap(gpioe_pul0); //取消GPIOE_PUL0映射
|
||||
misc_deregister(&misc_led_dev); //注销misc设备
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id misc_led_match_table[] = {
|
||||
{.compatible = "lite200,misc_led",},
|
||||
};
|
||||
|
||||
static struct platform_device_id misc_led_device_ids[] = {
|
||||
{.name = "misc_led",},
|
||||
};
|
||||
|
||||
static struct platform_driver misc_led_driver=
|
||||
{
|
||||
.probe = misc_led_probe,
|
||||
.remove = misc_led_remove,
|
||||
.driver={
|
||||
.name = "misc_led",
|
||||
.of_match_table = misc_led_match_table,
|
||||
},
|
||||
.id_table = misc_led_device_ids,
|
||||
};
|
||||
|
||||
static int misc_led_driver_init(void)
|
||||
{
|
||||
platform_driver_register(&misc_led_driver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void misc_led_driver_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&misc_led_driver);
|
||||
}
|
||||
|
||||
module_init(misc_led_driver_init);
|
||||
module_exit(misc_led_driver_exit);
|
||||
|
||||
MODULE_LICENSE("GPL"); //不加的话加载会有错误提醒
|
||||
MODULE_AUTHOR("1477153217@qq.com"); //作者
|
||||
MODULE_VERSION("0.1"); //版本
|
||||
MODULE_DESCRIPTION("misc_led_driver"); //简单的描述
|
||||
@ -1,141 +0,0 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/io.h> //含有ioremap函数iounmap函数
|
||||
#include <asm/uaccess.h> //含有copy_from_user函数和含有copy_to_user函数
|
||||
#include <linux/device.h> //含有类相关的设备函数
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/platform_device.h> //包含platform函数
|
||||
#include <linux/of.h> //包含设备树相关函数
|
||||
#include <linux/miscdevice.h> //包含misc相关函数
|
||||
|
||||
size_t *gpioe_cfg0; //存储虚拟地址到物理地址映射
|
||||
size_t *gpioe_cfg1; //存储虚拟地址到物理地址映射
|
||||
size_t *gpioe_data; //存储虚拟地址到物理地址映射
|
||||
size_t *gpioe_pul0; //存储虚拟地址到物理地址映射
|
||||
|
||||
static int misc_led_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
/* GPIOE配置 */
|
||||
*((volatile size_t*)gpioe_cfg1) &= ~(7<<16); //清除配置寄存器
|
||||
*((volatile size_t*)gpioe_cfg1) |= (1<<16); //配置GPIOE12为输出模式
|
||||
*((volatile size_t*)gpioe_pul0) &= ~(3<<16); //清除上/下拉寄存器
|
||||
*((volatile size_t*)gpioe_pul0) |= (1<<12); //配置GPIOE12为上拉模式
|
||||
printk(KERN_DEBUG"open led!!!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int misc_led_close(struct inode *inode, struct file *filp)
|
||||
{
|
||||
/* GPIOE配置 */
|
||||
printk(KERN_DEBUG"close led!!!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int misc_led_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
|
||||
{
|
||||
int ret;
|
||||
size_t status = *((volatile size_t*)gpioe_data);//获取GPIOE12状态
|
||||
ret = copy_to_user(buff,&status,4); //将内核空间拷贝到用户空间buff
|
||||
if(ret < 0)
|
||||
printk(KERN_DEBUG"read error!!!\n"); //输出信息
|
||||
else
|
||||
printk(KERN_DEBUG"read led ok!!!\n"); //输出信息
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int misc_led_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
|
||||
{
|
||||
int ret;
|
||||
size_t status;
|
||||
ret = copy_from_user(&status,buff,4); //将用户空间拷贝到内核空间的status
|
||||
if(ret < 0)
|
||||
printk(KERN_DEBUG"write error!!!\n"); //输出信息
|
||||
else
|
||||
printk(KERN_DEBUG"write led ok!!!\n"); //输出信息
|
||||
*((volatile size_t*)gpioe_data) &= ~(1<<12) ;//清除GPIOE12状态
|
||||
if(status)
|
||||
*((volatile size_t*)gpioe_data) |= (1<<12);//设置GPIOE12状态1
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations misc_led_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = misc_led_open,
|
||||
.read = misc_led_read,
|
||||
.write = misc_led_write,
|
||||
.release = misc_led_close,
|
||||
};
|
||||
|
||||
|
||||
static struct miscdevice misc_led_dev = {
|
||||
.minor = MISC_DYNAMIC_MINOR, //动态分配次设备号
|
||||
.name = "miscled",
|
||||
.fops = &misc_led_ops, //文件操作集
|
||||
};
|
||||
|
||||
static int misc_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
misc_register(&misc_led_dev); //注册misc设备
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取device中的GPIOE_CFG0
|
||||
gpioe_cfg0 = ioremap(res->start,(res->end - res->start)+1);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1); //获取device中的GPIOE_CFG1
|
||||
gpioe_cfg1 = ioremap(res->start,(res->end - res->start)+1);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 2); //获取device中的GPIOE_DATA
|
||||
gpioe_data = ioremap(res->start,(res->end - res->start)+1);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 3); //获取device中的GPIOE_PUL0
|
||||
gpioe_pul0 = ioremap(res->start,(res->end - res->start)+1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int misc_led_remove(struct platform_device *pdev)
|
||||
{
|
||||
iounmap(gpioe_cfg0); //取消GPIOE_CFG0映射
|
||||
iounmap(gpioe_cfg1); //取消GPIOE_CFG1映射
|
||||
iounmap(gpioe_data); //取消GPIOE_DATA映射
|
||||
iounmap(gpioe_pul0); //取消GPIOE_PUL0映射
|
||||
misc_deregister(&misc_led_dev); //注销misc设备
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id misc_led_match_table[] = {
|
||||
{.compatible = "lite200,misc_led",},
|
||||
};
|
||||
|
||||
static struct platform_device_id misc_led_device_ids[] = {
|
||||
{.name = "misc_led",},
|
||||
};
|
||||
|
||||
static struct platform_driver misc_led_driver=
|
||||
{
|
||||
.probe = misc_led_probe,
|
||||
.remove = misc_led_remove,
|
||||
.driver={
|
||||
.name = "misc_led",
|
||||
.of_match_table = misc_led_match_table,
|
||||
},
|
||||
.id_table = misc_led_device_ids,
|
||||
};
|
||||
|
||||
static int misc_led_driver_init(void)
|
||||
{
|
||||
platform_driver_register(&misc_led_driver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void misc_led_driver_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&misc_led_driver);
|
||||
}
|
||||
|
||||
module_init(misc_led_driver_init);
|
||||
module_exit(misc_led_driver_exit);
|
||||
|
||||
MODULE_LICENSE("GPL"); //不加的话加载会有错误提醒
|
||||
MODULE_AUTHOR("1477153217@qq.com"); //作者
|
||||
MODULE_VERSION("0.1"); //版本
|
||||
MODULE_DESCRIPTION("misc_led_driver"); //简单的描述
|
||||
@ -1,100 +0,0 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/io.h> //含有ioremap函数iounmap函数
|
||||
#include <asm/uaccess.h> //含有copy_from_user函数和含有copy_to_user函数
|
||||
#include <linux/device.h> //含有类相关的设备函数
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/kobject.h> //包含sysfs文件系统对象类
|
||||
#include <linux/sysfs.h> //包含sysfs操作文件函数
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#define GPIOE_CFG0 (0x01C20890)
|
||||
#define GPIOE_CFG1 (0x01C20894)
|
||||
#define GPIOE_DATA (0x01C208A0)
|
||||
#define GPIOE_PUL0 (0x01C208AC)
|
||||
|
||||
size_t *gpioe_cfg0; //存储虚拟地址到物理地址映射
|
||||
size_t *gpioe_cfg1; //存储虚拟地址到物理地址映射
|
||||
size_t *gpioe_data; //存储虚拟地址到物理地址映射
|
||||
size_t *gpioe_pul0; //存储虚拟地址到物理地址映射
|
||||
|
||||
static int led_status = 0; //定义一个led状态变量
|
||||
|
||||
static struct kobject *led_kobj; //定义一个led_kobj
|
||||
|
||||
|
||||
static ssize_t led_show(struct kobject* kobjs,struct kobj_attribute *attr,char *buf)
|
||||
{
|
||||
printk(KERN_INFO "Read led\n");
|
||||
return sprintf(buf,"The led_status status is = %d\n",led_status);
|
||||
}
|
||||
|
||||
static ssize_t led_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t count)
|
||||
{
|
||||
printk(KERN_INFO "led status store\n");
|
||||
if(0 == memcmp(buf,"on",2))
|
||||
{
|
||||
*((volatile size_t*)gpioe_data) &= ~(1<<12) ;//清除GPIOE12状态
|
||||
led_status = 1;
|
||||
}
|
||||
else if(0 == memcmp(buf,"off",3))
|
||||
{
|
||||
*((volatile size_t*)gpioe_data) |= (1<<12);//设置GPIOE12状态1
|
||||
led_status = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
printk(KERN_INFO "Not support cmd\n");
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//定义一个led_attr对象属性
|
||||
static struct kobj_attribute led_attr = __ATTR(led_status,0660,led_show,led_store);
|
||||
|
||||
static int __init sysfs_led_init(void)
|
||||
{
|
||||
int ret;
|
||||
led_kobj = kobject_create_and_add("sys_led",NULL);
|
||||
if(led_kobj == NULL)
|
||||
{
|
||||
printk(KERN_INFO"create led_kobj failed!\n");
|
||||
return -1;
|
||||
}
|
||||
ret = sysfs_create_file(led_kobj, &led_attr.attr);
|
||||
if(ret != 0)
|
||||
{
|
||||
printk(KERN_INFO"create sysfa file failed!\n");
|
||||
return -1;
|
||||
}
|
||||
gpioe_cfg0 = ioremap(GPIOE_CFG0,4); //将GPIOE_CFG0物理地址映射为虚拟地址
|
||||
gpioe_cfg1 = ioremap(GPIOE_CFG1,4); //将GPIOE_CFG1物理地址映射为虚拟地址
|
||||
gpioe_data = ioremap(GPIOE_DATA,4); //将GPIOE_DATA物理地址映射为虚拟地址
|
||||
gpioe_pul0 = ioremap(GPIOE_PUL0,4); //将GPIOE_PUL0物理地址映射为虚拟地址
|
||||
|
||||
*((volatile size_t*)gpioe_cfg1) &= ~(7<<16); //清除配置寄存器
|
||||
*((volatile size_t*)gpioe_cfg1) |= (1<<16); //配置GPIOE12为输出模式
|
||||
*((volatile size_t*)gpioe_pul0) &= ~(3<<16); //清除上/下拉寄存器
|
||||
*((volatile size_t*)gpioe_pul0) |= (1<<12); //配置GPIOE12为上拉模式
|
||||
|
||||
*((volatile size_t*)gpioe_data) &= ~(1<<12) ;//清除GPIOE12状态
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit sysfs_led_exit(void)
|
||||
{
|
||||
sysfs_remove_file(led_kobj,&led_attr.attr); //删除属性
|
||||
kobject_put(led_kobj); //删除对象
|
||||
printk(KERN_INFO "Goodbye!\n");
|
||||
}
|
||||
|
||||
module_init(sysfs_led_init);
|
||||
module_exit(sysfs_led_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("1477153217@qq.com");
|
||||
MODULE_DESCRIPTION("sysfs led");
|
||||
MODULE_VERSION("0.1");
|
||||
@ -1,11 +0,0 @@
|
||||
KERN_DIR = /home/lsw/licheepi/linux-5.7.1
|
||||
|
||||
all:
|
||||
make -C $(KERN_DIR) M=$(shell pwd) modules
|
||||
|
||||
clean:
|
||||
make -C $(KERN_DIR) M=$(shell pwd) modules clean
|
||||
rm -rf modules.order *.ko
|
||||
|
||||
obj-m += at24c02.o
|
||||
|
||||
@ -1,123 +0,0 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/io.h> //含有ioremap函数iounmap函数
|
||||
#include <asm/uaccess.h> //含有copy_from_user函数和含有copy_to_user函数
|
||||
#include <linux/device.h> //含有类相关的设备函数
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/platform_device.h> //包含platform函数
|
||||
#include <linux/of.h> //包含设备树相关函数
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kobject.h> //包含sysfs文件系统对象类
|
||||
#include <linux/sysfs.h> //包含sysfs操作文件函数
|
||||
#include <linux/regmap.h>
|
||||
|
||||
|
||||
static int recv[16] = {0}; //保存接收数据
|
||||
|
||||
|
||||
static struct kobject *at24c02_kobj; //定义一个led_kobj
|
||||
|
||||
static struct regmap *at24c02_regmap;
|
||||
|
||||
|
||||
static const struct regmap_config at24c02_config =
|
||||
{
|
||||
.reg_bits = 8, //寄存器8位
|
||||
.val_bits = 8, //数据8位
|
||||
.max_register = 255, //最大寄存器255个
|
||||
.cache_type = REGCACHE_NONE, //不使用cache
|
||||
.volatile_reg = false,
|
||||
};
|
||||
|
||||
static ssize_t at24c02_show(struct kobject* kobjs,struct kobj_attribute *attr,char *buf)
|
||||
{
|
||||
int ret;
|
||||
ret = regmap_write(at24c02_regmap,0x01,0); //先发写地址操作
|
||||
if(ret)
|
||||
{
|
||||
printk(KERN_ERR"write addr failed!\n");
|
||||
return ret;
|
||||
}
|
||||
ret = regmap_read(at24c02_regmap,0x01,&recv[0]); //然后发读数据操作
|
||||
if(ret)
|
||||
{
|
||||
printk(KERN_ERR"read addr failed!\n");
|
||||
return ret;
|
||||
}
|
||||
return sprintf(buf,"read status register=0x%x\n",recv[0]);
|
||||
}
|
||||
|
||||
static ssize_t at24c02_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(at24c02_regmap,0x01,0x2f);//写一个字节数据0x2f
|
||||
if(!ret)
|
||||
{
|
||||
printk(KERN_ERR"write data failed!\n");
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct kobj_attribute at24c02_attr = __ATTR(at24c02_dev,0660,at24c02_show,at24c02_store);
|
||||
|
||||
static int at24c02_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
at24c02_kobj = kobject_create_and_add("sys_at24c02",NULL);
|
||||
if(at24c02_kobj == NULL)
|
||||
{
|
||||
printk(KERN_INFO"create at24c02_kobj failed!\n");
|
||||
return -1;
|
||||
}
|
||||
ret = sysfs_create_file(at24c02_kobj, &at24c02_attr.attr);
|
||||
if(ret != 0)
|
||||
{
|
||||
printk(KERN_INFO"create at24c02_dev file failed!\n");
|
||||
return -1;
|
||||
}
|
||||
at24c02_regmap = regmap_init_i2c(client,&at24c02_config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at24c02_remove(struct i2c_client *client)
|
||||
{
|
||||
sysfs_remove_file(at24c02_kobj, &at24c02_attr.attr); //删除属性
|
||||
kobject_put(at24c02_kobj); //删除对象
|
||||
regmap_exit(at24c02_regmap);
|
||||
printk(KERN_INFO "exit sysfs at24c02!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id at24c02_id[] = {
|
||||
{ "test,at24c0x", 0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct of_device_id at24c02_of_match[] = {
|
||||
{ .compatible = "test,at24c0x"},
|
||||
{ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, at24c02_of_match);
|
||||
|
||||
static struct i2c_driver at24c02_driver = {
|
||||
.driver = {
|
||||
.name = "test,at24c0x",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = at24c02_of_match,
|
||||
},
|
||||
.probe = at24c02_probe,
|
||||
.remove = at24c02_remove,
|
||||
.id_table = at24c02_id,
|
||||
};
|
||||
|
||||
|
||||
module_i2c_driver(at24c02_driver);
|
||||
|
||||
MODULE_LICENSE("GPL"); //不加的话加载会有错误提醒
|
||||
MODULE_AUTHOR("1477153217@qq.com"); //作者
|
||||
MODULE_VERSION("0.1"); //版本
|
||||
MODULE_DESCRIPTION("at24c02_driver"); //简单的描述
|
||||
@ -1,11 +0,0 @@
|
||||
KERN_DIR = /home/lsw/licheepi/linux-5.7.1
|
||||
|
||||
all:
|
||||
make -C $(KERN_DIR) M=$(shell pwd) modules
|
||||
|
||||
clean:
|
||||
make -C $(KERN_DIR) M=$(shell pwd) modules clean
|
||||
rm -rf modules.order *.ko
|
||||
|
||||
obj-m +=w25q128.o
|
||||
|
||||
@ -1,115 +0,0 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/io.h> //含有ioremap函数iounmap函数
|
||||
#include <asm/uaccess.h> //含有copy_from_user函数和含有copy_to_user函数
|
||||
#include <linux/device.h> //含有类相关的设备函数
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/platform_device.h> //包含platform函数
|
||||
#include <linux/of.h> //包含设备树相关函数
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/kobject.h> //包含sysfs文件系统对象类
|
||||
#include <linux/sysfs.h> //包含sysfs操作文件函数
|
||||
|
||||
#define ERASE_OPCODE 0x20 //擦除操作码
|
||||
#define R_STS_OPCODE 0x35 //读状态操作码
|
||||
|
||||
static char tx_data[16] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
|
||||
static char rx_data[16] = {0};
|
||||
|
||||
static struct kobject *w25qxx_kobj; //定义一个led_kobj
|
||||
struct spi_transfer xfer;
|
||||
struct spi_device *w25qxx_spi; //保存spi设备结构体
|
||||
static ssize_t w25qxx_show(struct kobject* kobjs,struct kobj_attribute *attr,char *buf)
|
||||
{
|
||||
return sprintf(buf,"read status register=%d\n",rx_data[0]);
|
||||
}
|
||||
|
||||
static ssize_t w25qxx_store(struct kobject *kobj, struct kobj_attribute *attr,const char *buf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
int erase_addr=0x123456;
|
||||
tx_data[0]=ERASE_OPCODE;
|
||||
tx_data[1]=(erase_addr>>16)&0xff;
|
||||
tx_data[2]=(erase_addr>>8)&0xff;
|
||||
tx_data[3]=(erase_addr)&0xff;
|
||||
xfer.len = 4;
|
||||
ret = spi_sync_transfer(w25qxx_spi,&xfer,1); //擦除操作
|
||||
if(ret)
|
||||
{
|
||||
printk(KERN_INFO"erase w25q128 failed!\n");
|
||||
}
|
||||
|
||||
tx_data[0]=R_STS_OPCODE;
|
||||
ret = spi_write_then_read(w25qxx_spi,tx_data,1,rx_data,1);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct kobj_attribute w25qxx_attr = __ATTR(w25q128_dev,0660,w25qxx_show,w25qxx_store);
|
||||
|
||||
static void w25qxx_init(void)
|
||||
{
|
||||
xfer.tx_buf = tx_data;
|
||||
xfer.rx_buf = rx_data;
|
||||
xfer.len = sizeof(tx_data);
|
||||
xfer.bits_per_word = 8;
|
||||
memset(rx_data,0,16);
|
||||
}
|
||||
|
||||
static int w25qxx_probe(struct spi_device *spi)
|
||||
{
|
||||
int ret;
|
||||
w25qxx_kobj = kobject_create_and_add("sys_w25qxx",NULL);
|
||||
if(w25qxx_kobj == NULL)
|
||||
{
|
||||
printk(KERN_INFO"create w25qxx_kobj failed!\n");
|
||||
return -1;
|
||||
}
|
||||
ret = sysfs_create_file(w25qxx_kobj, &w25qxx_attr.attr);
|
||||
if(ret != 0)
|
||||
{
|
||||
printk(KERN_INFO"create w25q128_dev file failed!\n");
|
||||
return -1;
|
||||
}
|
||||
w25qxx_spi = spi_dev_get(spi);
|
||||
w25qxx_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int w25qxx_remove(struct spi_device *spi)
|
||||
{
|
||||
sysfs_remove_file(w25qxx_kobj, &w25qxx_attr.attr); //删除属性
|
||||
kobject_put(w25qxx_kobj); //删除对象
|
||||
printk(KERN_INFO "exit sysfs w25qxx!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct of_device_id w25qxx_match_table[] = {
|
||||
{.compatible = "test,w25qxx",},
|
||||
};
|
||||
|
||||
static struct spi_device_id w25qxx_ids[] = {
|
||||
{.name = "w25q128",},
|
||||
};
|
||||
|
||||
static struct spi_driver w25qxx_cdev = {
|
||||
.driver = {
|
||||
.name = "w25qxx",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = w25qxx_match_table,
|
||||
},
|
||||
.probe = w25qxx_probe,
|
||||
.remove = w25qxx_remove,
|
||||
.id_table = w25qxx_ids,
|
||||
};
|
||||
|
||||
|
||||
module_spi_driver(w25qxx_cdev);
|
||||
|
||||
MODULE_LICENSE("GPL"); //不加的话加载会有错误提醒
|
||||
MODULE_AUTHOR("1477153217@qq.com"); //作者
|
||||
MODULE_VERSION("0.1"); //版本
|
||||
MODULE_DESCRIPTION("w25qxx_driver"); //简单的描述
|
||||
@ -1,11 +0,0 @@
|
||||
KERN_DIR = /home/lsw/licheepi/linux-5.7.1
|
||||
|
||||
all:
|
||||
make -C $(KERN_DIR) M=$(shell pwd) modules
|
||||
|
||||
clean:
|
||||
make -C $(KERN_DIR) M=$(shell pwd) modules clean
|
||||
rm -rf modules.order *.ko
|
||||
|
||||
obj-m +=led_dev.o
|
||||
|
||||
@ -1,140 +0,0 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/io.h> //含有ioremap函数iounmap函数
|
||||
#include <asm/uaccess.h> //含有copy_from_user函数和含有copy_to_user函数
|
||||
#include <linux/device.h> //含有类相关的设备函数
|
||||
#include <linux/cdev.h>
|
||||
|
||||
#define GPIOE_CFG0 (0x01C20890)
|
||||
#define GPIOE_CFG1 (0x01C20894)
|
||||
#define GPIOE_DATA (0x01C208A0)
|
||||
#define GPIOE_PUL0 (0x01C208AC)
|
||||
|
||||
static dev_t led_dev_num; //定义一个设备号
|
||||
static struct cdev *led_dev; //定义一个设备管理结构体指针
|
||||
static struct class *led_class; //定义一个设备类
|
||||
static struct device *led0; //定义一个设备
|
||||
|
||||
size_t *gpioe_cfg0; //存储虚拟地址到物理地址映射
|
||||
size_t *gpioe_cfg1; //存储虚拟地址到物理地址映射
|
||||
size_t *gpioe_data; //存储虚拟地址到物理地址映射
|
||||
size_t *gpioe_pul0; //存储虚拟地址到物理地址映射
|
||||
|
||||
|
||||
static int led_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
/* GPIOE配置 */
|
||||
*((volatile size_t*)gpioe_cfg1) &= ~(7<<16); //清除配置寄存器
|
||||
*((volatile size_t*)gpioe_cfg1) |= (1<<16); //配置GPIOE12为输出模式
|
||||
*((volatile size_t*)gpioe_pul0) &= ~(3<<16); //清除上/下拉寄存器
|
||||
*((volatile size_t*)gpioe_pul0) |= (1<<12); //配置GPIOE12为上拉模式
|
||||
*((volatile size_t*)gpioe_data) &= ~(1<<16); //清除数据寄存器
|
||||
printk(KERN_DEBUG"open led!!!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int led_close(struct inode *inode, struct file *filp)
|
||||
{
|
||||
/* GPIOE配置 */
|
||||
*((volatile size_t*)gpioe_cfg1) &= ~(7<<16); //清除配置寄存器
|
||||
*((volatile size_t*)gpioe_cfg1) |= (7<<16); //配置GPIOE12为输出模式
|
||||
*((volatile size_t*)gpioe_pul0) &= ~(3<<16); //清除上/下拉寄存器
|
||||
*((volatile size_t*)gpioe_data) &= ~(1<<16); //清除数据寄存器
|
||||
printk(KERN_DEBUG"close led!!!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int led_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
|
||||
{
|
||||
int ret;
|
||||
size_t status = *((volatile size_t*)gpioe_data);//获取GPIOE12状态
|
||||
ret = copy_to_user(buff,&status,4); //将内核空间拷贝到用户空间buff
|
||||
if(ret < 0)
|
||||
printk(KERN_DEBUG"read error!!!\n"); //输出信息
|
||||
else
|
||||
printk(KERN_DEBUG"read led ok!!!\n"); //输出信息
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int led_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
|
||||
{
|
||||
int ret;
|
||||
size_t status;
|
||||
ret = copy_from_user(&status,buff,4); //将用户空间拷贝到内核空间的status
|
||||
if(ret < 0)
|
||||
printk(KERN_DEBUG"write error!!!\n"); //输出信息
|
||||
else
|
||||
printk(KERN_DEBUG"write led ok!!!\n"); //输出信息
|
||||
*((volatile size_t*)gpioe_data) = status;//设置GPIOE12状态
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct file_operations led_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = led_open,
|
||||
.read = led_read,
|
||||
.write = led_write,
|
||||
.release = led_close,
|
||||
};
|
||||
|
||||
static int __init led_init(void)
|
||||
{
|
||||
int ret;
|
||||
led_dev = cdev_alloc(); //动态申请一个设备结构体
|
||||
if(led_dev == NULL)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
ret = alloc_chrdev_region(&led_dev_num,0,1,"led"); //动态申请一个设备号
|
||||
if(ret == 0)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
led_dev->owner = THIS_MODULE; //初始化设备管理结构体的owner为THIS_MODULE
|
||||
led_dev->ops = &led_ops; //初始化设备操作函数指针为led_ops函数
|
||||
cdev_add(led_dev,led_dev_num,1); //将设备添加到内核中
|
||||
led_class = class_create(THIS_MODULE, "led_class"); //创建一个类
|
||||
if(led_class == NULL)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
led0 = device_create(led_class,NULL,led_dev_num,NULL,"led0"); //创建一个设备
|
||||
if(IS_ERR(led0))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
gpioe_cfg0 = ioremap(GPIOE_CFG0,4); //将GPIOE_CFG0物理地址映射为虚拟地址
|
||||
gpioe_cfg1 = ioremap(GPIOE_CFG1,4); //将GPIOE_CFG1物理地址映射为虚拟地址
|
||||
gpioe_data = ioremap(GPIOE_DATA,4); //将GPIOE_DATA物理地址映射为虚拟地址
|
||||
gpioe_pul0 = ioremap(GPIOE_PUL0,4); //将GPIOE_PUL0物理地址映射为虚拟地址
|
||||
|
||||
return 0;
|
||||
error:
|
||||
printk(KERN_WARNING"led_init failed!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void __exit led_exit(void)
|
||||
{
|
||||
cdev_del(led_dev); //从内核中删除设备管理结构体
|
||||
unregister_chrdev_region(led_dev_num,1); //注销设备号
|
||||
device_destroy(led_class,led_dev_num); //删除设备节点
|
||||
class_destroy(led_class); //删除设备类
|
||||
iounmap(gpioe_cfg0); //取消GPIOE_CFG0映射
|
||||
iounmap(gpioe_cfg1); //取消GPIOE_CFG1映射
|
||||
iounmap(gpioe_data); //取消GPIOE_DATA映射
|
||||
iounmap(gpioe_pul0); //取消GPIOE_PUL0映射
|
||||
}
|
||||
|
||||
module_init(led_init);
|
||||
module_exit(led_exit);
|
||||
|
||||
MODULE_LICENSE("GPL"); //不加的话加载会有错误提醒
|
||||
MODULE_AUTHOR("1477153217@qq.com"); //作者
|
||||
MODULE_VERSION("0.1"); //版本
|
||||
MODULE_DESCRIPTION("led_dev"); //简单的描述
|
||||
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user