[uboot] (番外篇)uboot dm-gpio使用方法以及工作流程

uboot gpio / 调用gpio_request_by_name_nodev来获取node节点中的"lgpio"属性,并转化为gpio_desc描述符,标志为输出。dm_gpio_get_value //获取gpio_desc描述的GPIO的值。dm_gpio_request //申请gpio_desc描述的GPIOdm_gpio_is_valid //判断该gpio_desc是否可用。---------------操作gpio--------------- 阅读详情

[uboot] uboot流程系列
[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)
[project X] tiny210(s5pv210)从存储设备加载代码到DDR
[uboot] (第一章)uboot流程——概述
[uboot] (第二章)uboot流程——uboot-spl编译流程
[uboot] (第三章)uboot流程——uboot-spl代码流程
[uboot] (第四章)uboot流程——uboot编译流程
[uboot] (第五章)uboot流程——uboot启动流程
[uboot] (番外篇)global_data介绍
[uboot] (番外篇)uboot relocation介绍
[uboot] (番外篇)uboot 驱动模型

建议先看《[uboot] (番外篇)uboot 驱动模型

=============================================================================================================

dm-gpio

一、dm-gpio架构

建议先参考《[uboot] (番外篇)uboot 驱动模型》搞懂uboot下的驱动模型。

1、dm-gpio架构图

如下:
这里写图片描述

2、说明

  • gpio core
    也在gpio uclass中实现,
    • 主要是为上层提供接口
    • 从dts中获取GPIO属性
    • 从gpio uclass的设备链表中获取到相应的udevice设备,并使用其操作集
  • gpio uclass

    • 链接属于该uclass的所有gpio udevice设备
    • 为gpio udevice的driver提供统一的操作集接口
  • bank和gpio

    • 有些平台上,将某些使用同一组寄存器的gpio构成一个bank,例如三星的s5pv210
    • 当然,并不是所有平台都有bank的概念,例如高通,高通的GPIO都有自己独立的寄存器,因此,可以将高通当成只有一个bank
  • gpio udevice

    • 一个bank对应一个gpio udevice,用bank中的偏移来表示具体的GPIO号
    • gpio udevice的driver就会根据bank以及offset对相应的寄存器上的相应的bit进行操作。

3、原理介绍

这里先简单介绍一下dm下gpio的工作原理

  • 一个bank对应一个udevice,udevice中私有数据中存放着该bank的信息,比如相应寄存器地址等等
  • 上层用gpio_desc描述符来描述一个GPIO,其中包括该GPIO所属的udevice、在bank内的偏移、以及标志位。
  • 上层通过调用gpio core的接口从dtsi获取到GPIO属性对应的gpio_desc描述符
  • 上层使用gpio_desc描述符来作为调用gpio core的操作接口的参数
  • gpio core从gpio_desc描述符提取udevice,并调用其driver中对应的操作集,以bank内的偏移作为其参数(这样driver就能判断出是哪个GPIO了)
  • driver中提取udevice的私有数据中的bank信息,并进行相应的操作

二、dm-gpio的使用示例

这里简单的以tiny210的led_1的闪烁为例子来介绍一下GPIO的使用。
虽然uboot中已经实现了led的uclass,但是我们这里先不使用这个uclass,只是简单的实现通过dm-gpio来控制一个led。

0、硬件简单说明(具体去参考原理图吧)

  • s5pv210的GPIO的地址空间
    参考《S5PV210_UM_REV1.1》2.1.2 SPECIAL FUNCTION REGISTER MAP,
    s5pv210的GPIO的地址空间为0xE020_0000开始的1000B的区域

  • 在tiny210上,有四个led,低电平为亮,高电平为灭

    • GPJ2_0 -> led_1
    • GPJ2_1 -> led_2
    • GPJ2_2 -> led_3
    • GPJ2_3 -> led_4
  • GPJ2这个bank的寄存器
    对应控制寄存器 0xE020_0280
    对应数据寄存器 0xE020_0284

1、dtsi中的定义

这里只说明GPIO引用的节点,不说明gpio控制器的节点,gpio控制器的节点在后面driver中进行说明
arch/arm/dts/s5pv210-tiny210.dts

    led_test {
        compatible = "dm-gpio,test";
        led1-gpio = <&gpj2 0 0>;      // 属性"led1-gpio",表示gpj2 bank的第0个gpio,0是值标志
        led2-gpio = <&gpj2 1 0>;    // gpj2 bank的第1个gpio,0是值标志
        led3-gpio = <&gpj2 2 0>;    // gpj2 bank的第2个gpio,0是值标志
        led4-gpio = <&gpj2 3 0>;    // gpj2 bank的第3个gpio,0是值标志
    };  

注意,这里<&gpj2 0 0>取决于driver是如何对这个属性进行转化的。并不是所有平台都是一样的。

2、驱动中从节点中获取一个GPIO

我们在board_late_init中来实现GPIO闪烁的功能
board/samsung/tiny210/board.c

int board_late_init(void)
{
    struct gpio_desc led1_gpio;
    int node;
    node = fdt_node_offset_by_compatible(gd->fdt_blob, 0, "dm-gpio,test");   
   // 注意,我们并没有使用dm模型的driver来匹配compatible = "dm-gpio,test"的节点,所以这里直接获取compatible = "dm-gpio,test"的节点,存放在node中
    if (node < 0)
    {   
        printf("===========================Don't find dm-gpio,test node\n");
        return -1; 
    }   

    gpio_request_by_name_nodev(gd->fdt_blob, node, "led1-gpio", 0, &led1_gpio, GPIOD_IS_OUT);
    // 调用gpio_request_by_name_nodev来获取node节点中的"led1-gpio"属性,并转化为gpio_desc描述符,标志为输出

    if (dm_gpio_is_valid(&led1_gpio))// 判断对应gpio_desc是否可用
    {   
        printf("===========================Get led1-gpio\n");
        while(1) 
        {   
            dm_gpio_set_value(&led1_gpio, 0);  // 调用dm_gpio_set_value将led1_gpio设置输出低电平
            mdelay(1000);
            dm_gpio_set_value(&led1_gpio, 1);  // 调用dm_gpio_set_value将led1_gpio设置输出高电平
            mdelay(1000);
        }
    }
    else
    {
        printf("===========================Can't get led1-gpio\n");
    }

3、简单说明

  • 在dtsi中将需要的GPIO以一定的格式在属性中描述,如下:
    led1-gpio = <&gpj2 0 0>;
  • 在驱动中调用gpio_request_by_name_nodev接口或者其他接口从dtsi节点中获取对应GPIO属性的gpio_desc描述符
  • 调用dm_gpio_is_valid判断该gpio_desc是否可用
  • 调用gpio core的dm操作接口,以gpio_desc为参数,实现控制GPIO的目的

后面介绍dm-gpio的实现

三、gpio uclass

建议先参考《[uboot] (番外篇)uboot 驱动模型》搞懂uboot下的驱动模型。
在gpio uclass中实现了两部分,

  • gpio uclass driver:gpio uclass驱动,提供gpio udevice绑定到uclass的设备链表之前和之后的一些操作,以及udevice的driver的操作集规范。
  • gpio core:为上层提供GPIO的操作接口

1、需要打开的宏

(1)CONFIG_DM
dm-gpio是基于uboot的DM实现的,关于uboot的DM可以参考《[uboot] (番外篇)uboot 驱动模型》。
所以需要先使能DM,也就是打开CONFIG_DM宏。
在configs/tiny210_defconfig中定义了如下:

CONFIG_DM=y

(2)打开CONFIG_DM_GPIO宏
在configs/tiny210_defconfig中定义了如下:

CONFIG_DM_GPIO=y

2、结构体说明

  • (1)gpio_desc
    前面也说过了,上层是通过gpio_desc来和gpio core进行交互的。
struct gpio_desc {
    struct udevice *dev;    /* Device, NULL for invalid GPIO */  //对应bank的udevice设备
    unsigned long flags;
    uint offset;        /* GPIO offset within the device */ // 该GPIO在bank内的偏移
};

offset对应bank内的偏移,通过offset+bank的gpio_base可以得到具体的GPIO号(用于兼容老版本的方式)。
调用uclass的接口可以从dts直接获得对应GPIO的描述符。DM框架下对GPIO的使用推荐使用这种方法。

  • (2)gpio_dev_priv
    每个gpio uclass设备链表下的udevice都有一部分属于uclass的私有数据。udevice->uclass_priv。
    都有一个这样的数据结构,提供给gpio uclass使用,让gpio uclass知道这个udevice中的gpio信息和情况。
struct gpio_dev_priv {
    const char *bank_name;  // udevice的名字,也是bank名称
    unsigned gpio_count; // 这个bank中的GPIO数量
    unsigned gpio_base; // 每个bank的gpio都占有gpio uclass的一部分连续的gpio空间,gpio_base则表示该bank的第一个GPIO号。
    char **name; //  阵列,每个gpio被request之后,都会有自己的label名称,存储在这里,可以防止GPIO request冲突
};
  • (3)标准dm-gpio的操作集合
struct dm_gpio_ops {
    int (*request)(struct udevice *dev, unsigned offset, const char *label); 
    int (*free)(struct udevice *dev, unsigned offset);
    int (*direction_input)(struct udevice *dev, unsigned offset);
    int (*direction_output)(struct udevice *dev, unsigned offset,
                int value);
    int (*get_value)(struct udevice *dev, unsigned offset);
    int (*set_value)(struct udevice *dev, unsigned offset, int value);
    int (*get_function)(struct udevice *dev, unsigned offset);
        /* 这里具体看注释 */
    int (*xlate)(struct udevice *dev, struct gpio_desc *desc,
             struct fdtdec_phandle_args *args);
};

注意都是以udevice和bank内的偏移为参数,驱动中可以根据udevice获取到对应bank的信息以及私有数据,然后根据偏移就可以确认出到底是哪个GPIO了。

3、gpio uclass driver

DM模型中gpio模块的uclass。定义模块加载前和加载后的操作函数等等。

UCLASS_DRIVER(gpio) = {
    .id     = UCLASS_GPIO,
    .name       = "gpio",
    .flags      = DM_UC_FLAG_SEQ_ALIAS,
    .post_probe = gpio_post_probe,
    .pre_remove = gpio_pre_remove,
    .per_device_auto_alloc_size = sizeof(struct gpio_dev_priv),
};
  • (1)gpio_post_probe
    gpio_post_probe会在gpio udevice probe之后被调用,实现如下:
static int gpio_post_probe(struct udevice *dev)
{
    struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); // 获取刚probe的udevice的提供给uclass使用私有数据

    uc_priv->name = calloc(uc_priv->gpio_count, sizeof(char *)); // 为私有数据中的GPIO label分配空间
    if (!uc_priv->name)
        return -ENOMEM;

    return gpio_renumber(NULL); // 重新分配GPIO空间
}

4、gpio core

主要负责通过gpio uclass为上层提供接口,

(1)接口说明
其中既提供了兼容老版本的接口,也提供了DM框架下的接口

  • DM框架下的接口
    注意,外部通过gpio_desc 来描述一个GPIO,所以这些接口都是以gpio_desc作为参数

    • gpio_request_by_name
      int gpio_request_by_name(struct udevice *dev, const char *list_name, int index, struct gpio_desc *desc, int flags)
      通过对应的udevice找到其dtsi节点中属性名为list_name的GPIO属性并转化为gpio_desc,并且request。
    • gpio_request_by_name_nodev
      int gpio_request_by_name_nodev(const void *blob, int node, const char *list_name, int index, struct gpio_desc *desc, int flags)
      通过对应的dtsi节点中属性名为list_name的GPIO属性并转化为gpio_desc,并且request。
    • dm_gpio_request
      int dm_gpio_request(struct gpio_desc *desc, const char *label)
      申请gpio_desc描述的GPIO
    • dm_gpio_get_value
      int dm_gpio_get_value(const struct gpio_desc *desc)
      获取gpio_desc描述的GPIO的值
    • dm_gpio_set_value
      int dm_gpio_set_value(const struct gpio_desc *desc, int value)
      设置gpio_desc描述的GPIO的值
    • dm_gpio_set_dir_flags
      int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
      设置gpio_desc描述的GPIO的输入输出方向,带标志
    • dm_gpio_set_dir
      int dm_gpio_set_dir(struct gpio_desc *desc)
      设置gpio_desc描述的GPIO的输入输出方向
    • dm_gpio_is_valid
      static inline bool dm_gpio_is_valid(const struct gpio_desc *desc)
      判断gpio_desc是否可用
  • 老接口:
    这些接口是为了兼容老版本的接口,注意,但是最终还是会调用DM框架下的接口

    • gpio_request
      int gpio_request(unsigned gpio, const char *label)
      申请一个GPIO
    • gpio_direction_input
      int gpio_direction_input(unsigned gpio)
      设置某个GPIO为输入
    • gpio_direction_output
      int gpio_direction_output(unsigned gpio, int value)
      设置某个GPIO为输出
    • gpio_get_value
      int gpio_get_value(unsigned gpio)
      获取某个GPIO上的值
    • gpio_set_value
      int gpio_set_value(unsigned gpio, int value)
      设置GPIO的值

(2)举例:dm_gpio_set_value

int dm_gpio_set_value(const struct gpio_desc *desc, int value)
{
    int ret;

    ret = check_reserved(desc, "set_value"); // 判断这个GPIO是否已经被request了,必须是request之后才能被使用
    if (ret)
        return ret;

    if (desc->flags & GPIOD_ACTIVE_LOW)
        value = !value;
    gpio_get_ops(desc->dev)->set_value(desc->dev, desc->offset, value);
        // 先获取对应udevice的driver,也就是对应bank的drvier的操作集中的set_value方法,
        // 然后以udevice、bank内的偏移,电平值为参数传入到set_value方法
        // 剩下的就是driver中的事了,driver中需要能根据udevice和bank内偏移操作到对应的GPIO上去
    return 0;
}

(3)举例:gpio_set_value

int gpio_set_value(unsigned gpio, int value)
{
    struct gpio_desc desc;
    int ret;

    ret = gpio_to_device(gpio, &desc); // 将GPIO转化为对应的gpio_desc描述符
        // 前面我们也说了,所有bank都占用uclass的gpio空间的一部分、并且是连续的不冲突的,因此,uclass core可以将对应的gpio转化为gpio_desc描述符
        // 具体实现自己看代码
    if (ret)
        return ret;
    return dm_gpio_set_value(&desc, value);
}

四、gpio driver

所有驱动都有自己的方式来解析gpio_desc,这里我们以s5pv210为例:
不同driver可能差异较大。这里只作为一个参考。
drivers/gpios5p_gpio.c

0、重点说明

所有bank都有对应的udevice,因此在绑定的过程都需要创建udevice中关于这个bank的私有数据。
s5pv210下这个私有数据是:

struct s5p_gpio_bank {
    unsigned int    con;
    unsigned int    dat;
    unsigned int    pull;
    unsigned int    drv;
    unsigned int    pdn_con;
    unsigned int    pdn_pull;
    unsigned char   res1[8];
};

其size刚好是一个bank的占有的寄存器的地址空间长度。并且意义也和寄存器中的对应。
另外,s5pv210并不会为每个bank都创建一个匹配节点(注意是匹配节点而不是节点,节点还是会用的,匹配节点是指带有compitable属性的节点),而是将所有bank的节点都放在一个匹配节点下,而driver会在bind这个匹配节点的时候,去probe这个节点下面的bank节点。而匹配节点是不做probe操作的。

1、dtsi中的定义

/{
    pinctrl: pinctrl@e0200000 {
        compatible = "samsung,s5pc110-pinctrl";   // 只有这个节点被匹配到,但是在这个节点bind的过程中,会去为子节点的bank创建对应udevice并且绑定到gpio uclass上,然后probe子节点
        reg = <0xe0200000 0x1000>;
        #address-cells = <1>;
        #size-cells = <1>;
        gpa0: gpa0 {
            gpio-controller;
            #gpio-cells = <2>;
        };  

        gpa1: gpa1 {
            gpio-controller;
            #gpio-cells = <2>;
        };  

        gpb: gpb {
            gpio-controller;
            #gpio-cells = <2>;
        };  

        gpc0: gpc0 {
            gpio-controller;
            #gpio-cells = <2>;
        };  
// 后面的bank这里不写了。。。
    }; 
}; 

注意这里的bank是有顺序的,必须和硬件上bank的顺序完全一致。

2、定义一个driver

具体成员的意义参考《[uboot] (番外篇)uboot 驱动模型

U_BOOT_DRIVER(gpio_exynos) = {
    .name   = "gpio_exynos",
    .id = UCLASS_GPIO, // 定义所属uclass的id
    .of_match = exynos_gpio_ids,
    .bind   = gpio_exynos_bind,
    .probe = gpio_exynos_probe,
    .priv_auto_alloc_size = sizeof(struct exynos_bank_info),
    .ops    = &gpio_exynos_ops,
};

3、实现exynos_gpio_ids

static const struct udevice_id exynos_gpio_ids[] = {
    { .compatible = "samsung,s5pc100-pinctrl" },
    { .compatible = "samsung,s5pc110-pinctrl" },
    { .compatible = "samsung,exynos4210-pinctrl" },
    { .compatible = "samsung,exynos4x12-pinctrl" },
    { .compatible = "samsung,exynos5250-pinctrl" },
    { .compatible = "samsung,exynos5420-pinctrl" },
    { }
};

4、实现gpio_exynos_bind

对应udevice绑定到uclass上所做的操作

static int gpio_exynos_bind(struct udevice *parent)
{
    struct exynos_gpio_platdata *plat = parent->platdata;
    struct s5p_gpio_bank *bank, *base;
    const void *blob = gd->fdt_blob;
    int node;

    /* If this is a child device, there is nothing to do here */
    if (plat)
        return 0;
        // 只有匹配的节点,也就是所有bank节点的父节点会做这个操作

    base = (struct s5p_gpio_bank *)dev_get_addr(parent); // 获取gpio寄存器的基地址
    for (node = fdt_first_subnode(blob, parent->of_offset), bank = base;
         node > 0;
         node = fdt_next_subnode(blob, node), bank++) { // 遍历所有子节点
        struct exynos_gpio_platdata *plat;
        struct udevice *dev;
        fdt_addr_t reg;
        int ret;

        if (!fdtdec_get_bool(blob, node, "gpio-controller")) // 判断是否有"gpio-controller"属性,也就是是否一个bank
            continue;
        plat = calloc(1, sizeof(*plat));    // 分配平台数据
        if (!plat)
            return -ENOMEM;

        plat->bank_name = fdt_get_name(blob, node, NULL);  // 设置平台数据的部分值
        ret = device_bind(parent, parent->driver, // 绑定子设备,这里会为bank创建udevice,并且绑定到gpio uclass中
                  plat->bank_name, plat, -1, &dev);
        if (ret)
            return ret;

        dev->of_offset = node; // 设备bank对应的udevice的node

        reg = dev_get_addr(dev); 
        if (reg != FDT_ADDR_T_NONE)
            bank = (struct s5p_gpio_bank *)((ulong)base + reg); // 所有bank的物理空间是以此排列的,并且长度都是一样的。

        plat->bank = bank; // 设置bank的物理地址

        debug("dev at %p: %s\n", bank, plat->bank_name);
    }

    return 0;
}

5、实现gpio_exynos_probe

static int gpio_exynos_probe(struct udevice *dev)
{
    struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
    struct exynos_bank_info *priv = dev->priv;
    struct exynos_gpio_platdata *plat = dev->platdata;

    /* Only child devices have ports */
    if (!plat)
        return 0;
        // 只有bank节点会做probe操作,而bank的父节点则不会做probe操作

    priv->bank = plat->bank; // 设置bank的私有数据

    uc_priv->gpio_count = GPIO_PER_BANK;  // 设置提供给uclass使用的私有数据gpio_dev_priv
    uc_priv->bank_name = plat->bank_name; // 设置提供给uclass使用的私有数据gpio_dev_priv

    return 0;
}

6、实现操作集

用于给gpio uclass提供udevice对应的bank操作集,必须使用dm_gpio_ops来进行定义

static const struct dm_gpio_ops gpio_exynos_ops = {
    .direction_input    = exynos_gpio_direction_input,
    .direction_output   = exynos_gpio_direction_output,
    .get_value      = exynos_gpio_get_value,
    .set_value      = exynos_gpio_set_value,
    .get_function       = exynos_gpio_get_function,
    .xlate          = exynos_gpio_xlate,
};

在这些操作方法中,最终会直接操作到GPIO对应的寄存器上去。
以exynos_gpio_set_value为例:

static int exynos_gpio_set_value(struct udevice *dev, unsigned offset,
                 int value)
// 以bank对应的udevice,以及bank内的偏移为参数
{
    struct exynos_bank_info *state = dev_get_priv(dev); // 获取平台私有数据,state->bank则是对应bank的寄存器地址
    s5p_gpio_set_value(state->bank, offset, value);
    return 0;
}

static void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en)
{
    unsigned int value;

    value = readl(&bank->dat); // 读bank中的data寄存器
    value &= ~DAT_MASK(gpio);
    if (en)
        value |= DAT_SET(gpio);
    writel(value, &bank->dat); // 写入
}

注意,上述还提供了转化方式exynos_gpio_xlate,负责解析dtsi的GPIO属性。所以,dtsi的GPIO的属性的格式就是取决于这里是怎么解析的。

uboot屏幕驱动流程分析 网上有很多关于uboot驱动DM的讲解,所以框架的部分就不过多赘述,写这篇博文的目的也是为了更好地了解uboot中的驱动模型,好了直接不如正文吧。在include/dm/uclass.h头文件里面定义了很多有DM驱动模型相关的函数,要明白这些函数是干嘛用的首先要明白代码里面驱动和设备之间的关系;上面这些函数有一个共同点,那就他们都是为了去获取structudevice*dev;if(!/*}...... 阅读详情

相关推荐

Android驱动框架整理之UBOOT框架

文章目录一、uboot框架1.1 文件系统1.2 对应的板级文件修改 本文主要整理一下安卓的一些框架,接触安卓半年了,写一篇文章做一次总结。 一、uboot框架 1.1 文件系统 uboot-imx$ ls api board common configs doc dts examples include Kconfig Licenses MAINTAINERS net README test arch cmd config.m

永不秃头的程序员的博客 1880

uboot GPIO Framework

了解uboot DM_GPIO 1.DM_GPIO 架构图 1.1.框架说明 gpio core 功能(gpio uclass中实现): 主要是为上层提供接口 从dts中获取GPIO属性 从gpio uclass的设备链表中获取到相应的udevice设备,并使用其操作集 gpio uclass 链接属于该uclass的所有gpio udevice设备 为gpio udevic...

weixin_41028621的博客 2298

[uboot] (番外篇uboot 驱动模型

uboot引入了驱动模型(driver model),这种驱动模型为驱动的定义和访问接口提供了统一的方法。提高了驱动之间的兼容性以及访问的标准型。 uboot驱动模型和kernel中的设备驱动模型类似,但是又有所区别。 在后续我们将驱动模型(driver model)简称为DM,其实在uboot里面也是这样简称的。 这篇文章里介绍的DM的流程以及如何使用

ooonebook的博客 4万+

通用接口(1)——GPIO控制

涉及文件: kernel/include/dt-bindings/pinctrl/rockchip.h //引脚pinctrl相关宏定义 选择GPIO4_C6引脚,对该IO引脚进行控制。该引脚在OK3399上做edp屏的pwm背光,不过只在选择主或副屏选择edp显示的情况下才做pwm,默认情况下是做GPIO。 原理图接口如下: 查阅用户资料-原厂资料中的《Rockchip RK3399 TRM V1.4 Part1》文档,检索gpio4c6,查看该引脚的功能复用: 可以看到该引脚默认的功能是gp

横山郡守的博客 2416

[uboot] uboot dm-gpio使用方法以及工作流程

[uboot] (番外篇uboot dm-gpio使用方法以及工作流程 kunkliu 2018-09-14 18:38:54 1313 收藏 2 分类专栏: uboot-ooonebook 转载地址:https://blog.csdn.net/ooonebook/article/details/53340441 [uboot] uboot流程系列:[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)[project X] tiny210(s5pv..

manshq163com的专栏 3301

ubootuboot 2020.04 DM驱动模式 -- 架构分析

相关文章 1.《【uboot】imx6ull uboot 2020.04源码下载和编译环境配置》 2.《【ubootuboot 2020.04 DM驱动模式 – Demo体验》 1. DM驱动模式简介 uboot引入了驱动模型(driver model)简称为DM,这种驱动模型为驱动的定义和访问接口提供了统一的方法。提高了驱动之间的兼容性以及访问的标准型。它主要包含以下4个成员: udevice:它就是指设备对象,一个driver的实例。 driver:udevice的驱动,硬件外设的driver。 u

ZHONGCAI0901的博客 6680

深入搞懂uboot的驱动模型(一)之 dm使用

简介uboot驱动模型,并主要通过分析一个led实例,介绍uboot驱动模型的使用方法

tang_vincent的博客 1049

Uboot DM9621网卡移植之路

前言 根据前面文章USB和Ethernet协议了解与原理图分析、DM_USB和DM_ETH模型简介所介绍,想必大家已经知道移植的流程应该是如何了,这里再简单的给出大致步骤,如下。 移植USB Host Controller驱动 使能USB3503 Hub 移植DM9621驱动 测试验证功能性 接下来就按照这几个步骤进行UbootDM9621网卡的移植之路,最终实现在Uboot使用网络命...

Jason_416的博客 4051

Linux驱动函数总结:gpio_set_value()

Linux内核中gpio是最简单,最常用的资源(和 interrupt ,dma,timer一样)驱动程序,应用程序都能够通过相应的接口使用gpiogpio使用0~MAX_INT之间的整数标识,不能使用负数,gpio与硬件体系密切相关的,不过linux有一个框架处理gpio,能够使用统一的接口来操作gpio.在讲gpio核心(gpiolib.c)之前先来看看gpio是怎么使用的。

uunubt的专栏 1万+

am5728通过DM框架配置GPIO管脚

以配置gpio3_31为例: 查看芯片手册: 这里gpio3_31为复用管脚,首先要配置寄存器将此管脚设置为gpio功能。 vim board/ti/am57xx/mux_data.h 所有多路复寄存器信息都在此定义:const struct pad_conf_entry core_padconf_array_essential_x15[] = { {GPMC_AD0, (M2 |

qq_35557608的博客 2022

用户层调用U-Boot Driver Model中的API接口

前言 关于U-Boot Driver Model的分析,网上有很多,可以直接搜索,或直接参考https://blog.csdn.net/ooonebook/category_6484145.html 很多时候,工程师都是只需要做应用开发,例如我只是希望电亮一个LED,根本就不用去了解DM(U-Boot Driver Model)的相关启动流程或绑定流程,仅仅只需要知道怎么调用即可。 另外,想了解U-Boot Driver Model,个人觉得要先懂得怎么使用,在网上搜了一遍,都是没有讲应用的,都是在将相关启

dengxinfa的博客 1174

gpio_direction_output vs gpio_set_value之间的使用关系

<br />在linux驱动中常常会碰到gpio_set_value(port_num,0/1)或gpio_direction_output (port_num,0/1)<br />  这两者有什么关系呢<br />gpio_set_value(port_num,0/1) 一般只是在这个GPIO口的寄存器上写上某个值,至于这个端口是否设置为输出,它就管不了!<br />而gpio_direction_output (port_num,0/1),在某个GPIO口写上某个值之后,还会把这个端口设置为输出模式。<

shuwu 2万+

gpio_set_value

. . . . .

John_chaos的博客 1561

Linux GPIO驱动部分函数

Linux GPIO端口驱动部分函数

weixin_61810331的博客 4472

2——GPIO子系统重要概念

16.2 GPIO子系统重要概念 16.2.1 引入 要操作GPIO引脚,先把所用引脚配置为GPIO功能,这通过Pinctrl子系统来实现。 然后就可以根据设置引脚方向(输入还是输出)、读值──获得电平状态,写值──输出高低电平。 以前我们通过寄存器来操作GPIO引脚,即使LED驱动程序,对于不同的板子它的代码也完全不同。 当BSP工程师实现了GPIO子系统后,我们就可以: a. 在设备树里指定GPIO引脚 b. 在驱动代码中: 使用GPIO子系统的标准函数获得GPIO、设置GPIO方向、读取/设置GPIO

韦东山嵌入式专栏 3947
上一篇: [uboot] (番外篇)uboot串口&console&stdio设备工作流程
下一篇: [uboot] uboot启动kernel篇(一)——Legacy-uImage & FIT-uImage
ooonebook
博客等级 码龄10年 1103粉丝 48原创
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值