君正X系列开发5---GPIO在用户空间使用&platform_device驱动&g

夜墨11111 2020-10-13 15:00:00 3711

可以通过导出gpio sys节点到用户空间,在用户空间操作。
内核的gpio驱动基于gpio子系统的实现,所以其他驱动程序可以通过内核提供的
libgpio
接口很方面的控制,例如,gpio_request_one,gpio_get_value,gpio_set_value

如果用gpio的方式控制led,需要改哪些呢?
驱动中选中gpioled,板级里找到LED_GPIO的宏,改成您自己用的gpio

X1000 的gpio 控制器有五组,A,B,C,D,Z。
支持输入输出和设备复用功能。内核的gpio 驱动程序是基于gpio 子系统架构编写的。应用
程序可以使用gpio_demo 进行测试。内核驱动可以在内核空间使用,也可以通过导出gpio sys 节点到用户空间,在用户空间进行操作

内核空间

文件介绍
gpio 一般在进行开发板设计的时候就已经固定好了,有的gpio 只能作为设备复用功能管脚,有的gpio 作为普通的输入输出和中断检测功能,对于固定设备复用的功能管脚在以下文件中定义:

arch/mips/xburst/soc-x1000/include/mach/platform.h
在arch/mips/xburst/soc-x1000/common/platform.c 会根据驱动配置,选中相应的设备功能管脚。

内核的gpio 驱动基于gpio 子系统实现,所以其它驱动程序可以通过内核提供的libgpio 接口,很方便的进行gpio 控制
例如gpio_request_one, gpio_get_value,gpio_set_value 等。

gpio 驱动文件所在位置:
arch/mips/xburst/soc-x1000/common/gpio.c

编译配置
内核通过配置CONFIG_GPIOLIB 选项可以使用gpio 功能,默认必须选上。
CONFIG_GPIOLIB:
Symbol: GPIOLIB [=y]
Type : boolean
Prompt: GPIO Support
Location:
-> Device Drivers
Defined at drivers/gpio/Kconfig:38
Depends on: ARCH_WANT_OPTIONAL_GPIOLIB [=n] || ARCH_REQUIRE_GPIOLIB [=y]

通过配置CONFIG_GPIO_SYSFS 选项,可以将gpio 导出到用户节点/sys/class/gpio 下,对该节点下的文件操作,可以控制gpio 输入输出。
Symbol: GPIO_SYSFS [=y]
Type : boolean
Prompt: /sys/class/gpio/... (sysfs interface)
Location:
-> Device Drivers
-> GPIO Support (GPIOLIB [=y])
Defined at drivers/gpio/Kconfig:69
Depends on: GPIOLIB [=y] && SYSFS [=y]

用户空间
在内核导出gpio 节点的前提下,可以操作/sys/class/gpio 节点,控制gpio 输入输出。
/sys/class/gpio/"export" ... 用户空间可以通过写其编号到这个文件,要求内核导出一个GPIO 的控制到用户空间。
例如: 如果内核代码没有申请GPIO #19,"echo 19 > export"
将会为GPIO #19 创建一个"gpio19" 节点。

"unexport" ... 导出到用户空间的逆操作。
例如: "echo 19 > unexport" 将会移除使用"export"文件导出的"gpio19" 节点。
GPIO 信号的路径类似/sys/class/gpio/gpio42/ (对于GPIO #42 来说),并有如下的读/写属性:
/sys/class/gpio/gpioN/

"direction" ... 读取得到"in" 或"out"。这个值通常运行写入。
写入"out" 时,其引脚的默认输出为低电平。为了确保无故障运行,"low" 或"high" 的电平值应该写入GPIO 的配置,作为初始输出值。
注意:如果内核不支持改变GPIO 的方向,或者在导出时内核代码没有明确允许用户空间可以重新配置GPIO 方向,那么这个属性将不存在。

"value" ... 读取得到0 (低电平) 或1 (高电平)。如果GPIO 配置为输出,这个值允许写操作。任何非零值都以高电平看待。

如果引脚可以配置为中断信号,且如果已经配置了产生中断的模式(见"edge"的描述),你可以对这个文件使用轮询操作(poll(2)),且轮询操作会在任何中断触发时返回。如果你使用轮询操作(poll(2)),请在events 中设置POLLPRI 和POLLERR。如果你使用轮询操作
(select(2)),请在exceptfds 设置你期望的文件描述符。在轮询操作(poll(2))返回之后,既可以通过lseek(2)操作读取sysfs 文件的开始部分,也可以关闭这个文件并重新打开它来读取数据。

"edge" ... 读取得到“none”、“rising”、“falling”或者“both”。
将这些字符串写入这个文件可以选择沿触发模式,会使得轮询操作(select(2))在"value"文件中返回。
这个文件仅有在这个引脚可以配置为可产生中断输入引脚时,才存在。
"active_low" ... 读取得到0 (假) 或1 (真)。写入任何非零值可以翻转这个属性的(读写)值。已存在或之后通过"edge"属性设置了"rising"

gpio操作 查看Documentation/gpio.txt文档

GPIO 模块

X1000的gpio 控制器有五组,A,B,C,D,Z。
支持输入输出和设备复用功能。内核的gpio 驱动程序是基于gpio 子系统架构编写的。应用程序可以使用gpio_demo 进行测试。内核驱动可以在内核空间使用,也可以通过导gpiosys 节点到用户空间,在用户空间进行操作。

内核空间
对于固定设备复用的功能管脚在以下文件中定义:
arch/mips/xburst/soc-x1000/include/mach/platform.h
在arch/mips/xburst/soc-x1000/common/platform.c 会根据驱动配置,选中相应的设备功能管脚。Platform.h中

/*
 * Copyright (C) 2010 Ingenic Semiconductor Inc.
 *
 *   Inthis file, here are some macro/device/function to
 * to help the board special file to organizeresources
 * on the chip.
 */
#ifndef __SOC_x1000_H__
#define __SOC_x1000_H__

/* devio define list */
/****************************************************************************************/
#define I2S_PORTB                          \
    {.name = "i2s", .port = GPIO_PORT_B, .func =GPIO_FUNC_1, .pins = 0x1f, }
/****************************************************************************************/
#define UART0_PORTC                            \
    {.name = "uart0", .port = GPIO_PORT_C, .func =GPIO_FUNC_0, .pins = 0x0f << 10, }
#define UART1_PORTA                            \
    {.name = "uart1-pa", .port = GPIO_PORT_A, .func =GPIO_FUNC_2, .pins = 0x3 << 4, }
#ifndef CONFIG_PRODUCT_X1000_BEETHOVEN
#define UART1_PORTD      
  {.name = "uart1-pd", .port = GPIO_PORT_D, .func =GPIO_FUNC_1, .pins = 0xf << 2, }
#else
#define UART1_PORTD                            \
    { .name = "uart1-pd", .port =GPIO_PORT_D, .func = GPIO_FUNC_1, .pins = 0x3 << 2, }
#endif
#define UART2_PORTA                            \
    {.name = "uart2-pa", .port = GPIO_PORT_A, .func =GPIO_FUNC_2, .pins = 0x3 << 2, }
#define UART2_PORTD                            \
    {.name = "uart2-pd", .port = GPIO_PORT_D, .func =GPIO_FUNC_0, .pins = 0x3 << 4 }
#define UART2_PORTC                            \
    {.name = "uart2-pc", .port = GPIO_PORT_C, .func =GPIO_FUNC_1, .pins = 0x1 << 31 }
/****************************************************************************************/

/* JZ SoC on Chip devices list*/
extern struct platform_device jz_codec_device;

extern struct platform_device jz_fb_device;

extern struct platform_device jz_uart0_device;
extern struct platform_device jz_uart1_device;
extern struct platform_device jz_uart2_device;

int jz_device_register(structplatform_device *pdev,void *pdata);

#endif

http://blog.csdn.net/ghostyu/article/details/6908805
在kernel/include/linux/platform.h中定义结构体

struct platform_device {
    const char *name;
    int     id;
    bool        id_auto;
    struct device  dev;
    u32     num_resources;
    struct resource    *resource;
    const struct platform_device_id   *id_entry;

    /* MFD cell pointer */
    struct mfd_cell *mfd_cell;

    /* arch specific additions */
    struct pdev_archdata   archdata;
};
函数extern intplatform_device_register(struct platform_device *);在文件kernel/drivers/base/platform.c中
/**
 * platform_device_register - add aplatform-level device
 * @pdev: platform device we're adding
 */
int platform_device_register(structplatform_device *pdev)
{
    device_initialize(&pdev->dev);
    arch_setup_pdev_archdata(pdev);
    return platform_device_add(pdev);
}
EXPORT_SYMBOL_GPL(platform_device_register);
文件arch/mips/xburst/soc-x1000/common/platform.c根据配置选项选中相应的设备功能引脚
#ifdef CONFIG_SERIAL_JZ47XX_UART2          //如果定义该选项
//在该板级配置文档中kernel/arch/mips/configs/halley2_nor_v10_linux_defconfig
static struct resource jz_uart2_resources[] = {
    [0] = {
        .start          = UART2_IOBASE,//基地址arch/mips/xburst/soc-x1000/include/soc
  //#defineUART0_IOBASE    0x10030000
        .end            = UART2_IOBASE + 0x1000 - 1,
        .flags          = IORESOURCE_MEM,
    },
    [1] = {
        .start          = IRQ_UART2,
        .end            = IRQ_UART2,
        .flags          = IORESOURCE_IRQ,
    },
#ifdef CONFIG_SERIAL_JZ47XX_UART2_DMA
    [2] = {
        .start          = JZDMA_REQ_UART2,
        .flags          = IORESOURCE_DMA,
    },
#endif
};

struct platform_device jz_uart2_device = {
    .name = "jz-uart",
    .id = 2,
    .num_resources  =ARRAY_SIZE(jz_uart2_resources),
    .resource       = jz_uart2_resources,
};
#endif

platform_device和platform_driver(一)
首先介绍一下注册一个驱动的步骤:
1、定义一个platform_driver结构
2、初始化这个结构,指定其probe、remove等函数,并初始化其中的driver变量
3、实现其probe、remove等函数
看platform_driver结构,定义于include/Linux/platform_device.h文件中:

struct platform_driver {
    int (*probe)(structplatform_device *);
    int (*remove)(structplatform_device *);
    void (*shutdown)(structplatform_device *);
    int (*suspend)(structplatform_device *, pm_message_t state);
    int (*resume)(structplatform_device *);
    struct device_driver driver;
    const struct platform_device_id *id_table;
};
声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
红包 1 3 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
夜墨11111
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区