【复习】linux之LED驱动的设备树方式

【前言】感谢陆老师

linux中led驱动(设备树)编程笔记

1.模块三要素

用到的头文件

#include <linux/kernel.h>
#include <linux/module.h>
1.1 初始化模块
int __init led_init(void)
{
  printk("led_init!!!\n");
  return 0;
}
module_init(led_init);
1.2 退出模块
void __exit led_exit(void)
{
  printk("led_exit!!!\n");
}
module_exit(led_exit);
1.3 模块签证
MODULE_LICENSE("GPL"):

2.platform总线的三个步骤

用到的头文件

#include <linux/platform_device.h>
#include <linux/of.h> //of_match_ptr
2.1 实例化platform_driver结构体
i)实例化回掉函数probe,并为成员.probe赋值
ii)实例化回掉函数remove,并为成员.remove赋值
iii)选择一种匹配方式进行匹配(设备树,ACPI,名字,ID四选一)
const struct of_device_id led_dt_table[]={
  {
    .compatible = "dt,led",
  },
  {

  },
};

struct platform_driver pdev{
  .probe = led_probe,
  .remove = led_remove,
  .driver = {
    .name = "led_platform",//名字必须加不然会报段错误(血的教训T_T)
    .of_match_table = of_match_ptr(led_dt_table),
  },
};
2.2 注册
//在led_init中注册
platform_driver_register(&pdev);
2.3 注销
//在led_exit中注销
platform_driver_unregister(&pdev);

3.字符设备框架流程(天龙八部)

用到的头文件

#include <linux/fs.h>
#include <linux/cdev.h>
3.1 申请设备号
#define DEV_MAJOR 500
#define DEV_MINOR 0
#define DEV_NUM   1
#define DEV_NAME  "ledx"
dev_t devno;
devno = MKDEV(DEV_MAJOR,DEV_MINOR);
3.2 注册设备号
ret = register_chrdev_region(devno,DEV_NUM,DEV_NAME);
if(ret < 0)
{
  printk("register_chrdev_region fail!!!\n");
  ret = alloc_chrdev_region(&devno,DEV_MINOR,DEV_NUM,DEV_NUM);
  if(ret < 0)
  {
    printk("alloc_chrdev_region fail!!!\n");
    return -1;
  }
}
else
  printk("register_chrdev_region success!!!\n");
printk("MAJOR=%d MINOR=%d\n",MAJOR(devno),MINOR(devno));
3.3 实例化cdev结构体
struct cdev led_cdev;
3.4 实例化file_operations结构体,并初始化
int led_open(struct inode *inode, struct file *file)
{
  printk("led_open!!!\n");
  return 0;
}
int led_close(struct inode *inode, struct file *file)
{
  printk("led_close!!!\n");
  return 0;
}
long led_ioctl (struct file *file, unsigned int cmd, unsigned long arg)
{
  printk("led_ioctl!!!\n");
  return 0;
}
struct file_operations fops={
  .owner = THIS_MODULE,
  .open = led_open,
  .release = led_close,
  .unlocked_ioctl = led_ioctl,
};
3.5 初始化cdev结构体
cdev_init(&led_cdev,&fops);
led_cdev.owner = THIS_MODULE;
3.6 注册cdev结构体
cdev_add(&led_cdev,devno,DEV_NUM);
3.7 注销cdev结构体
cdev_del(&led_cdev);
3.8 注销设备号
unregister_chrdev_region(devno,DEV_NUM);

4.自动创建设备节点

用到的头文件

#include <linux/device.h>
4.1 创建class
#define   CLS_NAME  "cls_led"
struct class *cls;
cls = class_create(THIS_MODULE,CLS_NAME);
if(IS_ERR(cls))
{
  printk("class_create fail!!!\n");
  return -1;
}
4.2 创建设备节点
#define   NODE_LED "led"
device_create(cls,NULL,devno,NULL,NODE_LED);
4.3 注销设备节点
device_destroy(cls,devno);
4.4 注销class
class_destroy(cls);

5.修改设备树文件

5.1 打开设备树文件

cd linux-3.14.2/arch/arm/boot/dts
vim xxx.dts

5.2 修改设备树文件

在最后面添加

led_platform {
  compatible = "dt,led";
  reg = <寄存器地址 字节数 寄存器地址 字节数>;
}
6.make编译并测试

Makefile

ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /home/linux/kernel/linux-3.14.2/  这里是编译好并能正常运行的内核的路径
PWD ?= $(shell pwd)
modules:
  $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
  $(MAKE) -C $(KERNELDIR) M=$(PWD) clean
.PHONY: modules clean
else
  obj-m += led_dt.o 模块源码的.o文件
endif
7.led部分程序

驱动的框架搭好了,现在开始LED部分的编程

//在全局中
static volatile unsigned int * gpx2con;
static volatile unsigned int * gpx1con;
static volatile unsigned int * gpf3con;
static volatile unsigned int * gpx2dat;
static volatile unsigned int * gpx1dat;
static volatile unsigned int * gpf3dat;

//在led_probe函数中
gpx2con = ioremap(pdev->resource[0].start,pdev->resource[0].end - pdev->resource[0].start);
gpx1con = ioremap(pdev->resource[1].start,pdev->resource[1].end - pdev->resource[1].start);
gpf3con = ioremap(pdev->resource[2].start,pdev->resource[2].end - pdev->resource[2].start);

gpx2dat = gpx2con + 1;
gpx1dat = gpx1con + 1;
gpf3dat = gpf3con + 1;

*gpx2con = (*gpx2con &~ (0xf << 28))|(0x1 << 28);
*gpx1con = (*gpx1con &~ (0xf <<  0))|(0x1 <<  0);
*gpf3con = (*gpf3con &~ (0xf << 16))|(0x1 << 16);
*gpf3con = (*gpf3con &~ (0xf << 20))|(0x1 << 20);

*gpx2dat = (*gpx2dat |  (0x1 << 7));
*gpx1dat = (*gpx1dat |  (0x1 << 0));
*gpf3dat = (*gpf3dat |  (0x1 << 4));
*gpf3dat = (*gpf3dat |  (0x1 << 5));

//在led_remove中
iounmap(gpx2con);
iounmap(gpx1con);
iounmap(gpf3con);

原理图
schema

寄存器设置
register

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值