设备树学习之(二)点灯

2023-10-30

开发板:tiny4412SDK + S702 + 4GB Flash 
要移植的内核版本:Linux-4.4.0 (支持device tree) 
u-boot版本:友善之臂自带的 U-Boot 2010.12 
busybox版本:busybox 1.25

目标: 
学习设备树中GPIO控制器的使用,实现配置引脚为输出功能,写简单的字符设备驱动程序,实现点亮LED。

原理图: 
这里写图片描述 
tiny4412 核心板上有6颗LED,这里我们只控制其中4颗,它们分别接在GPM4_0、GPM4_1、GPM4_2、GPM4_3 引脚。想要点亮LED,首先得配置引脚为输出功能,输出低电平时LED点亮,高电平时,LED熄灭。重点在于设备树中GPIO控制器资源的使用。

设备树参考:

参考:Samsung GPIO and Pin Mux/Config controller
Example 1: A pin-controller node with pin groups.
    pinctrl_0: pinctrl@11400000 { 
        compatible = "samsung,exynos4210-pinctrl";
        reg = <0x11400000 0x1000>;
        interrupts = <0 47 0>;
        /* ... */
        uart0_data: uart0-data { 
            samsung,pins = "gpa0-0", "gpa0-1";
            samsung,pin-function = <2>;
            samsung,pin-pud = <0>;
            samsung,pin-drv = <0>; 
        };
Example 3: A uart client node that supports 'default' and 'flow-control' states.
    uart@13800000 { 
        compatible = "samsung,exynos4210-uart";
        reg = <0x13800000 0x100>;
        interrupts = <0 52 0>;
        pinctrl-names = "default", "flow-control;
        pinctrl-0 = <&uart0_data>;
        pinctrl-1 = <&uart0_data &uart0_fctl>; 
    };
  "samsung,pins" property of the child node. The following pin configuration properties are supported.
  - samsung,pin-val: Initial value of pin output buffer.
  - samsung,pin-pud: Pull up/down configuration.
  - samsung,pin-drv: Drive strength configuration.
  - samsung,pin-pud-pdn: Pull up/down configuration in power down mode.
  - samsung,pin-drv-pdn: Drive strength configuration in power down mode.
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

设备树:

&pinctrl@11000000 {
        led_demo: led{
                samsung,pins = "gpm4-0", "gpm4-1" ,"gpm4-2", "gpm4-3";
                samsung,pin-function = <0x1>;   //1为输出
                samsung,pin-pud = <0x0>;        //没有上拉
                samsung,pin-drv = <0x0>;        //驱动强度?
        };
}; 

led_pin {
    compatible         = "tiny4412,led_demo";
    pinctrl-names = "led_demo";
    pinctrl-0 = <&led_demo>;
    tiny4412,int_gpio1 = <&gpm4 0 GPIO_ACTIVE_HIGH>;
    tiny4412,int_gpio2 = <&gpm4 1 GPIO_ACTIVE_HIGH>;
    tiny4412,int_gpio3 = <&gpm4 2 GPIO_ACTIVE_HIGH>;
    tiny4412,int_gpio4 = <&gpm4 3 GPIO_ACTIVE_HIGH>;
};

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

我们在 pinctrl 中增加了 led 节点,它代表了一种引脚功能,比如这里设置的 gpm4_0、gpm4_1、gpm4_2、gpm4_3,引脚功能为 0x01 输出,无上拉等等。在其它地方,我们可以引用它,来表示引脚支持的功能。 
下面我们增加了 led_pin 节点,它有一个属性 pinctrl-names = “led_demo”,这是我们给引脚功能状态起的名字,如果支持多种功能,可以是字符串列表的形式。字符串的个数要和下面 pinctrl-n 的个数对应,pinctrl-0 引用了我们前面定义的那个将引脚设置为输出功能的属性。 
在代码中,我们可以用过 pinctrl-names 来获得特定的引脚功能,并设置它。如果 pinctrl-names 为 “default”,那么这种功能状态将设置为默认的引脚状态,代码中无需处理。

代码片段:

static int led_probe(struct platform_device *pdev) {

    struct device *dev = &pdev->dev;
    dev_t devid;
    struct pinctrl *pctrl;
    struct pinctrl_state *pstate;
    pctrl = devm_pinctrl_get(dev);
    if(pctrl == NULL)
    {
        printk("devm_pinctrl_get error\n");
    }
    pstate = pinctrl_lookup_state(pctrl, "led_demo");
    if(pstate == NULL)
    {
        printk("pinctrl_lookup_state error\n");
    }
    pinctrl_select_state(pctrl, pstate);//设置为输出模式 
    printk("enter %s\n",__func__);
    led1 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio1", 0);;
    led2 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio2", 0);;
    led3 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio3", 0);;
    led4 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio4", 0);;
    if(led1 <= 0)
    {
        printk("%s error\n",__func__);
        return -EINVAL;
    }
    else
    {
        printk("led1 %d\n",led1);
        printk("led2 %d\n",led2);
        printk("led3 %d\n",led3);
        printk("led4 %d\n",led4);
        devm_gpio_request_one(dev, led1, GPIOF_OUT_INIT_HIGH, "LED1");
        devm_gpio_request_one(dev, led2, GPIOF_OUT_INIT_HIGH, "LED2");
        devm_gpio_request_one(dev, led3, GPIOF_OUT_INIT_HIGH, "LED3");
        devm_gpio_request_one(dev, led4, GPIOF_OUT_INIT_HIGH, "LED4");
    }

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

完整代码:

#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>

#define LED_CNT   4

static int  major;
static struct cdev  led_cdev;   //内核中用cdev描述一个字符设备
static struct class *cls;
static int led1,led2,led3,led4;

static ssize_t led_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
{
    char buf;
    int minor = iminor(file->f_inode);

    printk("minor is %d\n",minor);
    printk("%s\n",__func__);
    if(count != 1){
        printk("count != 1\n"); 
        return 1;
    }
    if (copy_from_user(&buf, user_buf, count))
        return -EFAULT;

    printk("rcv %d\n",buf);
    if(buf == 0x01)
    {
        switch(minor){
        case 0:
            gpio_set_value(led1, 0);
            break;
        case 1:
            gpio_set_value(led2, 0);
            break;
        case 2:
            gpio_set_value(led3, 0);
            break;
        case 3:
            gpio_set_value(led4, 0);
            break;
        default:
            printk("%s rcv minor error\n",__func__);
        }                       
    }
    else if(buf == 0x0)
    {
        switch(minor){
        case 0:
            gpio_set_value(led1, 1);
            break;
        case 1:
            gpio_set_value(led2, 1);
            break;
        case 2:
            gpio_set_value(led3, 1);
            break;
        case 3:
            gpio_set_value(led4, 1);
            break;
        default:
            printk("%s rcv minor error\n",__func__);
        }       
    }
}
static int led_open(struct inode *inode, struct file *file)
{
    printk("led_open\n");
    return 0;
}

static struct file_operations led_fops = {
    .owner = THIS_MODULE,
    .open  = led_open,
    .write = led_write,
};

static int led_probe(struct platform_device *pdev) {

    struct device *dev = &pdev->dev;
    dev_t devid;
    struct pinctrl *pctrl;
    struct pinctrl_state *pstate;
    pctrl = devm_pinctrl_get(dev);
    if(pctrl == NULL)
    {
        printk("devm_pinctrl_get error\n");
    }
    pstate = pinctrl_lookup_state(pctrl, "led_demo");
    if(pstate == NULL)
    {
        printk("pinctrl_lookup_state error\n");
    }
    pinctrl_select_state(pctrl, pstate);//设置为输出模式 
    printk("enter %s\n",__func__);
    led1 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio1", 0);;
    led2 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio2", 0);;
    led3 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio3", 0);;
    led4 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio4", 0);;
    if(led1 <= 0)
    {
        printk("%s error\n",__func__);
        return -EINVAL;
    }
    else
    {
        printk("led1 %d\n",led1);
        printk("led2 %d\n",led2);
        printk("led3 %d\n",led3);
        printk("led4 %d\n",led4);
        devm_gpio_request_one(dev, led1, GPIOF_OUT_INIT_HIGH, "LED1");
        devm_gpio_request_one(dev, led2, GPIOF_OUT_INIT_HIGH, "LED2");
        devm_gpio_request_one(dev, led3, GPIOF_OUT_INIT_HIGH, "LED3");
        devm_gpio_request_one(dev, led4, GPIOF_OUT_INIT_HIGH, "LED4");
    }

    if(alloc_chrdev_region(&devid, 0, LED_CNT, "led") < 0)/* (major,0~1) 对应 hello_fops, (major, 2~255)都不对应hello_fops */
    {
        printk("%s ERROR\n",__func__);
        goto error;
    }
    major = MAJOR(devid);                     

    cdev_init(&led_cdev, &led_fops);        //绑定文件操作函数
    cdev_add(&led_cdev, devid, LED_CNT);    //注册到内核

    cls = class_create(THIS_MODULE, "led"); //创建led类,向类中添加设备,mdev会帮我们创建设备节点
    device_create(cls, NULL, MKDEV(major, 0), NULL, "led0"); 
    device_create(cls, NULL, MKDEV(major, 1), NULL, "led1"); 
    device_create(cls, NULL, MKDEV(major, 2), NULL, "led2"); 
    device_create(cls, NULL, MKDEV(major, 3), NULL, "led3"); 

error:
    unregister_chrdev_region(MKDEV(major, 0), LED_CNT);
    return 0;
}

static int led_remove(struct platform_device *pdev) {

    printk("enter %s\n",__func__);
    device_destroy(cls, MKDEV(major, 0));
    device_destroy(cls, MKDEV(major, 1));
    device_destroy(cls, MKDEV(major, 2));
    device_destroy(cls, MKDEV(major, 3));
    class_destroy(cls);

    cdev_del(&led_cdev);
    unregister_chrdev_region(MKDEV(major, 0), LED_CNT);

    printk("%s enter.\n", __func__);
    return 0;
}

static const struct of_device_id led_dt_ids[] = {
    { .compatible = "tiny4412,led_demo", },
    {},
};

MODULE_DEVICE_TABLE(of, led_dt_ids);

static struct platform_driver led_driver = {
    .driver        = {
        .name      = "led_demo",
        .of_match_table    = of_match_ptr(led_dt_ids),
    },
    .probe         = led_probe,
    .remove        = led_remove,
};

static int led_init(void){
    int ret;
    printk("enter %s\n",__func__);
    ret = platform_driver_register(&led_driver);
    if (ret)
        printk(KERN_ERR "led demo: probe failed: %d\n", ret);

    return ret; 
}

static void led_exit(void)
{
    printk("enter %s\n",__func__);
    platform_driver_unregister(&led_driver);
}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL");
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

设备树学习之(二)点灯 的相关文章

随机推荐

  • TurboPower Async Professional 在Delphi2010及Delphi7中的安装

    这里我们介绍一下TurboPower Async Professional 串口控件的安装方法 Delphi 2010 1 下载http sourceforge net projects tpapro 2 解压 在Delphi2010下找到
  • python正则表达式爬取【豆瓣电影top250】(新手向)

    最近在学崔大的 网络爬虫开发与实战 学到正则表达式那块儿 便迎来了自己的第一个实战项目 话不多说 正式进入正文 本次爬虫工具使用的是pycharm 已经提前安装好了所有包 安装方式 file Settings Project Interpr
  • 双亲委派机制及其部分源码分析

    双亲委派机制 双亲委派机制 我理解的 双亲委派机制 简单来讲就是 类加载器加载类的时候是 自顶向下 的过程来加载 详情如下 在某个加载器进行类加载是 会逐级向上找到他最终的父类 BootstrapClassLoader 先进行加载 逐级向下
  • List元素移除-迭代器删除

    Exception in thread main java util ConcurrentModificationException异常解决方案 使用迭代器方式删除List元素内容 当直接用List的remove移除元素时 会报如上异常 比
  • Hinton关于RBM的代码注解之(三)mnistclassify.m

    mnistclssify m clear all close all maxepoch 50 最大迭代次数 numhid 500 numpen 500 numpen2 2000 对应的1 2 3层隐含层单元的个数 fprintf 1 Con
  • C++ 的封装、继承、多态

    面向对象的三个基本特征 面向对象的三个基本特征是 封装 继承 多态 封装可以隐藏实现细节 使得代码模块化 继承可以扩展已存在的代码模块 类 多态则是为了实现另一个目的 接口重用 它们的目的都是为了 代码重用 封装 目的 隐藏实现细节 使得代
  • Python 控制 Raspberry Pi 云台多舵机

    多舵机控制 使用 Python 和云台机制构造进行 Raspberry Pi 相机定位 所需材料 在本教程中 我们将探索如何在 Raspberry Pi 上使用 Python 控制多个舵机 我们的目标是使用云台机制来定位相机 PiCam 如
  • 【测试开发】基于 MeterSphere 的接口测试流程

    基于 MeterSphere 的接口测试流程 MeterSphere 接口测试模块提供了 接口定义 接口自动化 等接口测试相关功能 用户可以使用树状多级模块来分级分组管理项目下的接口列表 创建执行接口用例测试接口 组合编排多个接口用例进行场
  • 电子产品推荐系统的设计与实现

    其他项目 点击作者主页 目录 1 系统简介 2 系统相关技术 2 1 JSP技术 2 2 B S架构 2 3 MySQL数据库技术 2 4 SSM 3 需求分析 3 1 系统功能需求分析 3 2 系统非功能需求分析 4 系统设计 4 1 系
  • websocket协议

    WebSocket是一种在Web应用程序中实现实时双向通信的协议 一种在单个TCP连接上进行全双工通信的协议 它使得客户端和服务器之间的数据交换变得更加简单 允许服务端主动向客户端推送数据 WebSocket 与 HTTP 2 一样 其实都
  • Java如何对一个对象进行深拷贝?

    深拷贝实现代码 https github com wudashan java deep copy 介绍 在Java语言里 当我们需要拷贝一个对象时 有两种类型的拷贝 浅拷贝与深拷贝 浅拷贝只是拷贝了源对象的地址 所以源对象的值发生变化时 拷
  • 【Transformers】第 1 章 :Hello Transformers

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • QWidget: Must construct a QApplication before a QWidget 请按任意键继续. . .

    系列文章目录 文章目录 系列文章目录 前言 一 错误原因 前言 一 错误原因 在调试examples工程时 遇到编译报错 QWidget Must construct a QApplication before a QWidget 根据字面
  • 打开软件或游戏出现找不到d3dcompiler_43.dll文件如何解决?

    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题 如果是新手第一时间会认为是软件或游戏出错了 其实并不是这样 其主要原因就是你电脑系统的该dll文件丢失了或者损坏了 这时你只需下载这个d3dcompiler 43 dll文件进行安装
  • SpringBoot的日志配置 logging.file.path和logging.file.name不能同时生效

    这里写自定义目录标题 logging file path和logging file name logging file path和logging file name logging file path data logs lra sdk l
  • day20 网络编程(上)

    day20 网络编程 上 课程目标 掌握网络相关的基础知识并可以基于Python开发程序 基于网络进行数据传输 课程概要 网络必备基础 网络编程 Python代码 B S和C S架构 1 必备基础 你必须了解的网络相关设备和基础概念 1 1
  • Caffe学习之自定义创建新的Layer层

    caffe源码中已经帮我封装好了各种各样的layer 但是有时候现有的layer不能满足设计的网络要求 这个时候需要自己定义一个新的layer 本文参考here 进行简单讲解 具体方式如下 一 创建 hpp文件 1 添加你的layer头文件
  • 利用PIFU-HD生成自己的三维人体图像

    这个小项目本身是在研一的时候调的 记录一下过程 以后在别的电脑上配置就容易点 我是在windows系统下配置的 gpu贼拉跨 报错很多 欢迎借鉴 总有一款错误适合你 然后友情提示 跑项目就是会遇到各种各样的错误 请需要的小伙伴耐心看 遇到问
  • 简析区块链的特点和每个分层的作用

    区块链技术在这几年不停的发展更新 相应的区块链服务应用和技术也逐渐走向成熟 区块链技术相对于行业内的内来说就相对熟悉一些 但对于那些还未接触这些技术知识的人来说就相当陌生 区块链技术有什么特点 区块链底层系统有哪些分层 对应的作用分别是什么
  • 设备树学习之(二)点灯

    开发板 tiny4412SDK S702 4GB Flash 要移植的内核版本 Linux 4 4 0 支持device tree u boot版本 友善之臂自带的 U Boot 2010 12 busybox版本 busybox 1 25