【BeagleBone Black Rev. C试用体验】+设备树驱动
来源:互联网 发布:python tcp 保持连接 编辑:程序博客网 时间:2024/06/09 20:19
感觉设备树写驱动是未来的潮流。。。下面我们来讲讲设备树驱动开发。。
设备树语法我们这就不说了,去下面链接自己参考吧:
http://www.cnblogs.com/xiaojiang1025/p/6131381.html
一、修改设备树:
设备树文件在arch/arm/boot/dts目录下am335x-boneblack.dts文件
先贴代码:
修改的地方我都有标注。。。
compatible是用来匹配的。。。
pinctrl-names用来匹配pinctrl设置信息。。。
source_gpios用来获取io信息。。。
我们用的是gpio1_12,设置mode7,且为输出模式。。。
二、总线驱动
platform总线驱动这里就不介绍了。我也讲不明白。感兴趣的可以去 了解,以前学习的时候都是自己写个device再写个driver然后匹配。
现在有设备树了devcie省去了,减少了很大的代码冗余。。。。
写驱动编译有错误不要紧,一条条出解决,查问题。这个驱动刚写好时,一编译刷刷的一排error下来,看到额眼睛都花了,但是一个个看过去还是能解决的。无非就是头文件没包含
语法有问题。。调用的变量类型有问题。。
下面贴个简单的框架:
接下来就是填充代码了,先填充probe函数,再填充remove函数,接下来注册init和exit函数。。
最后把file_operations结构体填充完。。
完整代码:
驱动我写了很多打印函数。。很方便调试。。
printk函数的打印信息是通过串口打印出来的。
还要改下打印级别:
用源码的调试吧。。
测试代码:
设备树语法我们这就不说了,去下面链接自己参考吧:
http://www.cnblogs.com/xiaojiang1025/p/6131381.html
一、修改设备树:
设备树文件在arch/arm/boot/dts目录下am335x-boneblack.dts文件
先贴代码:
/* add by Sourcelink */
/ {
model = "TI AM335x BeagleBoneBlack";
compatible = "ti,am335x-bone", "ti,am33xx";
cpus {
cpu@0 {
cpu0-supply = <&dcdc2_reg>;
};
};
/* add by Sourcelink */
source_gpio {
compatible = "sourcelink_gpio";
pinctrl-names = "sourcelink_gpio";
pinctrl-0 = <&sourcelink_pin>;
source_gpios = <&gpio2 12 0>;
};
};
&am33xx_pinmux {
rstctl_pins: pinmux_rstctl_pins {
pinctrl-single,pins = <
/* eMMC_RSTn */
0x50 0x17 /* gpmc_a4.gpio1_20, OUTPUT | MODE7 | PULLUP */
>;
};
/* add by Sourcelink */
sourcelink_pin: pinmux_source_pins {
pinctrl-single,pins = <
0x30 0x7 /* gpmc_ad12.gpio1_12, OUTPUT | MODE7 */
>;
};
};
compatible是用来匹配的。。。
pinctrl-names用来匹配pinctrl设置信息。。。
source_gpios用来获取io信息。。。
我们用的是gpio1_12,设置mode7,且为输出模式。。。
切记gpio的地址标号是从1开始的。。。gpio1对应的是GPIO0_x的地址,我就是这出了问题一直没有调出来。。。
引脚的复用都是从800h地址开始:
对应管脚从gpio0_0开始四个字节开始增加,所以gpio1_12偏移对应:4*12 = 48 = 0x30
二、总线驱动
platform总线驱动这里就不介绍了。我也讲不明白。感兴趣的可以去 了解,以前学习的时候都是自己写个device再写个driver然后匹配。
现在有设备树了devcie省去了,减少了很大的代码冗余。。。。
写驱动编译有错误不要紧,一条条出解决,查问题。这个驱动刚写好时,一编译刷刷的一排error下来,看到额眼睛都花了,但是一个个看过去还是能解决的。无非就是头文件没包含
语法有问题。。调用的变量类型有问题。。
下面贴个简单的框架:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/pinctrl/consumer.h>
static int gpio_drv_open(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t gpio_drv_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
{
int ret;
return ret;
}
struct file_operations gpio_drv_fops = {
.owner = THIS_MODULE,
.open = gpio_drv_open,
.write = gpio_drv_write,
};
static const struct of_device_id of_gpio_fortree_match[] = {
{ .compatible = "sourcelink_gpio", },
{},
};
static int gpio_fortree_probe(struct platform_device *pdev)
{
return 0;
}
static int gpio_fortree_remove(struct platform_device *pdev)
{
return 0;
}
static struct platform_driver gpio_fortree_driver = {
.probe = gpio_fortree_probe,
.remove = gpio_fortree_remove,
.driver = {
.name = "sourcelink_gpio",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_gpio_fortree_match),
},
};
static int gpio_fortree_init(void)
{
int ret;
return ret;
}
static void gpio_fortree_exit(void)
{
}
module_init(gpio_fortree_init);
module_exit(gpio_fortree_exit);
MODULE_AUTHOR("Sourcelink");
MODULE_DESCRIPTION("device tree driver");
MODULE_LICENSE("GPL");
接下来就是填充代码了,先填充probe函数,再填充remove函数,接下来注册init和exit函数。。
最后把file_operations结构体填充完。。
完整代码:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/pinctrl/consumer.h>
static int source_gpio;
static struct cdev gpio_drv_cdev; //内核中用cdev描述一个字符设备
static struct class *gpio_drv_class;
static int minor;
static int gpio_drv_open(struct inode *inode, struct file *file)
{
minor = iminor(inode); /* 获取文件的次设备号 */
printk("gpio_drv_open\n");
printk("minor:%d \n", minor);
return 0;
}
static ssize_t gpio_drv_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
{
int ret = 0;
int val = 0;
// 返回错误个数,正确返回0
if (copy_from_user((int *)&val, user_buf, count)) {
ret = -EFAULT;
} else {
*ppos += count;
ret = count;
}
printk("val:%d \n", val);
if (val == 1) {
switch(minor){
case 0:
gpio_set_value(source_gpio, 1);
printk("gpio_on\n");
break;
}
} else {
switch(minor){
case 0:
gpio_set_value(source_gpio, 0);
printk("gpio_off\n");
break;
}
}
return ret;
}
struct file_operations gpio_drv_fops = {
.owner = THIS_MODULE,
.open = gpio_drv_open,
.write = gpio_drv_write,
};
static const struct of_device_id of_gpio_fortree_match[] = {
{ .compatible = "sourcelink_gpio", },
{},
};
static int major;
static int gpio_fortree_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
dev_t devid;
struct pinctrl *pctrl;
struct pinctrl_state *pstate;
printk("enter %s\n",__func__);
pctrl = devm_pinctrl_get(dev);
if(pctrl == NULL)
{
printk("devm_pinctrl_get error\n");
}
pstate = pinctrl_lookup_state(pctrl, "sourcelink_gpio");
if(pstate == NULL)
{
printk("pinctrl_lookup_state error\n");
}
pinctrl_select_state(pctrl, pstate); /* gpmc_a12.gpio1_12, OUTPUT | MODE7 */
source_gpio = of_get_named_gpio(dev->of_node, "source_gpios", 0);
if (source_gpio <= 0) {
printk("of_get_named_gpio error!!!\n");
return -EINVAL;
} else {
printk("sourcelink_gpio is %d\n", source_gpio);
if (devm_gpio_request_one(dev, source_gpio, GPIOF_OUT_INIT_LOW, "source_gpio44") != 0) {
printk("devm_gpio_request_one error!!!\n");
}
}
if(alloc_chrdev_region(&devid, 0, 1, "sourcelink") < 0)/* (major,0~1) 对应 hello_fops, (major, 2~255)都不对应hello_fops */
{
printk("%s ERROR\n",__func__);
goto error;
}
major = MAJOR(devid);
cdev_init(&gpio_drv_cdev, &gpio_drv_fops); //绑定文件操作函数
cdev_add(&gpio_drv_cdev, devid, 1); //注册到内核
gpio_drv_class = class_create(THIS_MODULE, "sourcelink"); //创建sourcelink类,向类中添加设备,mdev会帮我们创建设备节点
device_create(gpio_drv_class, NULL, MKDEV(major, 0), NULL, "source_gpio44");
return 0;
error:
unregister_chrdev_region(MKDEV(major, 0), 1);
return -EINVAL;
}
static int gpio_fortree_remove(struct platform_device *pdev)
{
printk("enter %s\n",__func__);
device_destroy(gpio_drv_class, MKDEV(major, 0));
class_destroy(gpio_drv_class);
cdev_del(&gpio_drv_cdev);
unregister_chrdev_region(MKDEV(major, 0), 1);
return 0;
}
static struct platform_driver gpio_fortree_driver = {
.probe = gpio_fortree_probe,
.remove = gpio_fortree_remove,
.driver = {
.name = "sourcelink_gpio",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_gpio_fortree_match),
},
};
static int gpio_fortree_init(void)
{
int ret;
printk("enter %s\n",__func__);
ret = platform_driver_register(&gpio_fortree_driver);
if (ret)
printk(KERN_ERR "gpio_fortree_probe: probe failed: %d\n", ret);
return ret;
}
static void gpio_fortree_exit(void)
{
printk("enter %s\n",__func__);
platform_driver_unregister(&gpio_fortree_driver);
}
module_init(gpio_fortree_init);
module_exit(gpio_fortree_exit);
MODULE_AUTHOR("Sourcelink");
MODULE_DESCRIPTION("device tree driver");
MODULE_LICENSE("GPL");
printk函数的打印信息是通过串口打印出来的。
还要改下打印级别:
echo 5 > /proc/sys/kernel/printk
用源码的调试吧。。
测试代码:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int fd;
int led_state = 0;
int i;
fd = open("/dev/source_gpio44", O_RDWR);
if (fd < 0)
printf("can't open!\n");
#if 0
if (argc != 2) {
printf("Usage: \n");
printf("%s <on|off>\n", argv[0]);
return -1;
}
if (strcmp(argv[1], "on") == 0)
led_state = 1;
else
led_state = 0;
if (write (fd, &led_state, 1)) {
printf("write successful!\n");
}
#else
for (i = 0; i < 10; i++) {
switch (led_state) {
case 0:
write (fd, &led_state, 1);
printf("led off!\n");
led_state = 1;
break;
case 1:
write (fd, &led_state, 1);
printf("led on!\n");
led_state = 0;
break;
}
sleep(1);
}
#endif
close(fd);
return 0;
}
阅读全文
0 0
- 【BeagleBone Black Rev. C试用体验】+设备树驱动
- 【BeagleBone Black Rev. C试用体验】+固件更换
- 【BeagleBone Black Rev. C试用体验】+内核更新
- Beaglebone Black LED驱动
- BeagleBone Black GPIO IRQ 驱动
- BeagleBone Black教程之BeagleBone Black设备的连接
- Beaglebone Black——修改设备树文件
- 单板计算机Beaglebone-Black首发上手体验
- 【NanoPi Duo试用体验】+一个简单的字符设备驱动
- Beaglebone Black开发板安装驱动
- Uboot Beaglebone Black Usb驱动分析
- RTEMS-libbsd 实现beaglebone black USB驱动
- 使用Beaglebone Black的I2C (二)——使用C语言和i2c-dev驱动
- BeagleBone Black编程学习_eclipse C/C++
- 单板计算机Beaglebone-Black首发上手体验(1)
- Beaglebone black日记
- beaglebone black 安装 vnc
- BeagleBone Black: 网页服务器
- MongoDB使用小结:一些常用操作分享
- java SE教程06
- 解决下载文件时中文乱码问题
- Qt无法用UTF-8编辑问题
- Hibernate--根据实体类获得表名、主键名、字段名(与Spring集成)(一)
- 【BeagleBone Black Rev. C试用体验】+设备树驱动
- 人脸识别:(抓拍+识别)
- String Split 获取空值--limit参数作用
- 对于相同喜好的用户,电商高手用Spark MLlib代码如何操作?
- [列联相关] 列联系数计算及假设检验
- JAVA中字符串比较equals()和equalsIgnoreCase()的区别
- (Android)解决react-native打包好后启动白屏的问题(react-native-splash-screen)
- SLAM 的初步学习(一)--ubuntu14.04 下安装 opencv3.2
- oracle多表联合查询加gruop by处理