GPIO驱动模型

linux设备驱动程序——gpio控制 在gpio初始化的函数中添加这个接口,在加载完成之后查看/sys/class/gpio/目录下是否有相应的gpio$num(这里是gpio26)文件(需要注意的是,在上例中,当用户程序打开设备时才进行gpio的初始化,关闭文件时释放gpio的资源,所以需要打开文件再操作)。当用户程序执行时,用户程序一直获取用户的输入,根据用户输入"on"或者"off",然后将其写入设备文件,触发系统调用,设备文件根据设备号找到内核中相应的file_operation结构体,相应write函数被调用,执行相应的点灯操作。 阅读详情
  1. 一、概述
  2. GPIO是嵌入式系统最简单、最常用的资源了,比如点亮LED,控制蜂鸣器,输出高低电平,检测按键,等等。GPIO分输入和输出,在davinci linux中,有关GPIO的最底层的寄存器驱动,\arch\arm\mach-davinci目录下的gpio.c,这个是寄存器级的驱动,搞过单片机MCU的朋友应该比较熟悉寄存器级的驱动。

  3. GPIO的驱动主要就是读取GPIO口的状态,或者设置GPIO口的状态。就是这么简单,但是为了能够写好的这个驱动,在LINUX上作了一些软件上的分层。为了让其它驱动可以方便的操作到GPIO,在LINUX里实现了对GPIO操作的统一接口,这个接口实则上就是GPIO驱动的框架,具体的实现文件为gpiolib.c在配置内核的时候,我们必须使用CONFIG_GENERIC_GPIO这个宏来支持GPIO驱动。

  4. GPIO是与硬件体系密切相关的,linux提供一个模型来让驱动统一处理GPIO,即各个板卡都有实现自己的gpio_chip控制模块:request, free, input,output, get,set,irq...然后把控制模块注册到内核中,这时会改变全局gpio数组:gpio_desc[]. 当用户请求gpio时,就会到这个数组中找到,并调用这个GPIO对应的gpio_chip的处理函数。gpio实现为一组可用的 gpio_chip, 由驱动传入对应 gpio的全局序号去 request, dataout ,datain, free. 这时会调用gpio_chip中具体的实现。
  5. gpio是一组可控件的脚,由多个寄存器同时控制。通过设置对应的寄存器可以达到设置GPIO口对应状态与功能。数据状态,输入输出方向,清零,中断(那个边沿触发), 一般是一组(bank)一组的。
  6. 寄存器读写函数: __raw_writel() __raw_writeb() __raw_readl() __raw_readb()

  7. 二、linux 中GPIO模型的结构
  8. //表示一个gpio口,含对应的gpio_chip.
  9. //对于每一个gpio,都有一个gpio描述符,这个描述符包含了这个gpio所属的控制器即chip和一些标志,label等
  10. struct gpio_desc {
  11.     struct gpio_chip    *chip;
  12.     unsigned long    flags;
  13.     /* flag symbols are bit numbers */
  14.     #define FLAG_REQUESTED 0
  15.     #define FLAG_IS_OUT 1
  16.     #define FLAG_RESERVED 2
  17.     #define FLAG_EXPORT 3 /* protected by sysfs_lock */
  18.     #define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */
  19.     #define FLAG_TRIG_FALL 5 /* trigger on falling edge */
  20.     #define FLAG_TRIG_RISE 6 /* trigger on rising edge */
  21.     #define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */
  22.     #define FLAG_OPEN_DRAIN 8 /* Gpio is open drain type */
  23.     #define FLAG_OPEN_SOURCE 9 /* Gpio is open source type */
  24.     
  25.     #define ID_SHIFT 16 /* add new flags before this one */ 
  26.     #define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1)
  27.     #define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
  28.  
  29. #ifdef CONFIG_DEBUG_FS
  30.     const char    *label;
  31. #endif
  32. };
  33. //采用了一个具有ARCH_NR_GPIOS大小的gpio描述符数组。这个描述符数组便代表了系统所有的gpio。
  34. static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];//ARCH_NR_GPIOS=144,即系统现在有144个GPIO口

  35. //static struct davinci_gpio_controller chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];//将144个GPIO分成每32个一组
  36. //一组GPIO控制器结构,例如GPIO0和GPIO1是一组(共32个GPIO口),共用一组寄存器,所以GPIO0和GPIO1荷载一起用chips[0]来控制
  37. ///共有144个GPIO,分为4组(GPIO0~GPIO8),每组有2个banks(即GPIO0和GPIO1为1组),每组最多可以有32个GPIO,每组的控制寄存器空间有10个。
  38. struct davinci_gpio_controller {
  39.     struct gpio_chip    chip;//每组对应的gpio_chip
  40.     int            irq_base;//每组对应的中断
  41.     spinlock_t        lock;//自旋锁
  42.     void __iomem        *regs;//每组的寄存器地址
  43.     void __iomem        *set_data;//设置数据寄存器地址
  44.     void __iomem        *clr_data;//清除数据寄存器地址
  45.     void __iomem        *in_data;//输入数据寄存器地址
  46. }; 

  47. //每一个davinci_gpio_controller结构都对应于一个gpio_chip结构,gpio_chip既可看成是davinci_gpio_controller结构的补充
  48. //表示一个gpio controller.通过这个结构抽象化所有的GPIO源,而让板上其它的模块可以用相同的接口调用使用这些GPIO。
  49. struct gpio_chip {
  50.     const char    *label;
  51.     struct device    *dev;
  52.     struct module    *owner; 
  53.     int    (*request)(struct gpio_chip *chip,unsigned offset);//请求gpio
  54.     void    *free)(struct gpio_chip *chip,unsigned offset);//释放gpio
  55.     int    (*get_direction)(struct gpio_chip *chip,unsigned offset);
  56.     int    (*direction_input)(struct gpio_chip *chip,unsigned offset);//配置gpio为输入,返回当前gpio状态
  57.     int    (*get)(struct gpio_chip *chip,unsigned offset);//获取gpio的状态
  58.     int    (*direction_output)(struct gpio_chip *chip,unsigned offset, int value);//配置gpio为输出,并设置为value
  59.     int    (*set_debounce)(struct gpio_chip *chip,unsigned offset, unsigned debounce);//设置消抖动时间,尤其是gpio按键时有用
  60.     void    (*set)(struct gpio_chip *chip,unsigned offset, int value);//设置gpio为value值
  61.     int    (*to_irq)(struct gpio_chip *chip,unsigned offset);//把gpio号转换为中断号
  62.     void    (*dbg_show)(struct seq_file *s,struct gpio_chip *chip);
  63.     int    base;// 这个gpio控制器的gpio开始编号
  64.     u16    ngpio;//这个gpio控制器说控制的gpio数
  65.     const char    *const *names;
  66.     unsigned    can_sleep:1;
  67.     unsigned    exported:1;
  68.  
  69. #if defined(CONFIG_OF_GPIO)
  70.     struct device_node *of_node;
  71.     int of_gpio_n_cells;
  72.     int (*of_xlate)(struct gpio_chip *gc,const struct of_phandle_args *gpiospec, u32 *flags);
  73. #endif
  74. #ifdef CONFIG_PINCTRL
  75.     struct list_head pin_ranges;
  76. #endif
  77. };

  78. //GPIO寄存器结构
  79. struct davinci_gpio_regs {
  80.     u32 dir; // gpio方向设置寄存器 
  81.     u32 out_data; // gpio设置为输出时,表示输出状态(0或1) 
  82.     u32 set_data; // gpio设置为输出时,用于输出高电平 
  83.     u32 clr_data; // gpio设置为输出时,用于输出低电平 
  84.     u32 in_data; // gpio设置为输入时,用于读取输入值 
  85.     u32 set_rising; // gpio中断上升沿触发设置 
  86.     u32 clr_rising; // gpio中断上升沿触发清除 
  87.     u32 set_falling; // gpio中断下降沿触发设置 
  88.     u32 clr_falling; // gpio中断下降沿触发清除 
  89.     u32 intstat; // gpio中断状态位,由硬件设置,可读取,写1时清除。 
  90. };

  91. struct gpio {
  92.     unsigned gpio;//gpio号
  93.     unsigned long flags;//gpio标志
  94.     const char *label;//gpio名
  95. };

  96. 三、GPIO的初始化
  97. 1.首先设置GPIO的管脚复用寄存器
  98. static __init void da850_evm_init(void)
  99. {
  100.     //.......
  101.     ret = davinci_cfg_reg_list(da850_gpio_test_pins);
  102.     if (ret) 
  103.         pr_warning("da850_evm_init: gpio test ping mux setup failed: %d\n", ret);
  104.     //.......
  105. }

  106. 2.根据板级结构的资源初始化chips数组,此函数在系统初始化时自动调用
  107. static struct davinci_gpio_controller chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];//将144个GPIO分成每32个一组
  108. static int __init davinci_gpio_setup(void)
  109. {
  110.     int i, base;
  111.     unsigned ngpio;
  112.     struct davinci_soc_info *soc_info = &davinci_soc_info;//板级资源结构
  113.     struct davinci_gpio_regs *regs;

  114.     if (soc_info->gpio_type != GPIO_TYPE_DAVINCI)//判断GPIO类型
  115.         return 0;

  116.     ngpio = soc_info->gpio_num;//GPIO数量144
  117.     if (ngpio == 0) {
  118.         pr_err("GPIO setup: how many GPIOs?\n");
  119.         return -EINVAL;
  120.     }

  121.     if (WARN_ON(DAVINCI_N_GPIO < ngpio))//DAVINCI_N_GPIO=144
  122.         ngpio = DAVINCI_N_GPIO;

  123.     gpio_base = ioremap(soc_info->gpio_base, SZ_4K);//将GPIO的寄存器物理基地址(#define DA8XX_GPIO_BASE        0x01e26000)映射到内存中
  124.     if (WARN_ON(!gpio_base))
  125.         return -ENOMEM;
  126.     
  127.     //共有144个GPIO,分为4组(GPIO0~GPIO8),每组有2个banks(即GPIO0和GPIO1为1组),每组最多可以有32个GPIO,每组的控制寄存器空间有10个。
  128.     //chips[0]--chips[4],base值为0,32,64,96,128,ngpio分别为:32,32,32,32,16
  129.     for (i = 0, base = 0; base < ngpio; i++, base += 32) {
  130.         chips[i].chip.label = "DaVinci";
  131.         //设置操作函数
  132.         chips[i].chip.direction_input = davinci_direction_in;
  133.         chips[i].chip.get = davinci_gpio_get;
  134.         chips[i].chip.direction_output = davinci_direction_out;
  135.         chips[i].chip.set = davinci_gpio_set;

  136.         chips[i].chip.base = base;//每一组开始的GPIO号
  137.         //每组控制的GPIO个数,一般为32个
  138.         chips[i].chip.ngpio = ngpio - base;
  139.         if (chips[i].chip.ngpio > 32)
  140.             chips[i].chip.ngpio = 32;

  141.         spin_lock_init(&chips[i].lock);
  142.         //找到这组GPIO的寄存器地址,初始化chips结构
  143.         regs = gpio2regs(base);
  144.         chips[i].regs = regs;//设置每组的寄存器
  145.         chips[i].set_data = ?s->set_data;
  146.         chips[i].clr_data = ?s->clr_data;
  147.         chips[i].in_data = ?s->in_data;
  148.         
  149.         gpiochip_add(&chips[i].chip);//注册gpio_chip
  150.     }
  151.     //chips数组添加到板级资源中
  152.     soc_info->gpio_ctlrs = chips;
  153.     soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);

  154.     davinci_gpio_irq_setup();//设置GPIO中断
  155.     return 0;
  156. }
  157. pure_initcall(davinci_gpio_setup);//linux初始化时会自动调用

  158. static struct davinci_gpio_regs __iomem __init *gpio2regs(unsigned gpio)
  159. {
  160.     void __iomem *ptr;
  161.     
  162.     //根据GPIO的基地址累加,其中基地址(gpio_base+0)是REVID(Revision ID Register)寄存器
  163.     //(gpio_base+8)是BINTEN (GPIO Interrupt Per-Bank Enable Register)寄存器
  164.     //所以第一组寄存器从基地址+0x10开始
  165.     if (gpio < 32 * 1)
  166.         ptr = gpio_base + 0x10;
  167.     else if (gpio < 32 * 2)
  168.         ptr = gpio_base + 0x38;
  169.     else if (gpio < 32 * 3)
  170.         ptr = gpio_base + 0x60;
  171.     else if (gpio < 32 * 4)
  172.         ptr = gpio_base + 0x88;
  173.     else if (gpio < 32 * 5)
  174.         ptr = gpio_base + 0xb0;
  175.     else
  176.         ptr = NULL;
  177.     return ptr;
  178. }

  179. int gpiochip_add(struct gpio_chip *chip)
  180. {
  181.     unsigned long    flags;
  182.     int        status = 0;
  183.     unsigned    id;
  184.     int        base = chip->base;
  185.     
  186.     //检测gpio的有效性,判断这组GPIO的起始号是否在有效范围内
  187.     if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))&& base >= 0) {
  188.         status = -EINVAL;
  189.         goto fail;
  190.     }

  191.     spin_lock_irqsave(&gpio_lock, flags);
  192.     
  193.     //如果这组GPIO的起始号小于0,则动态的分配gpio的开始索引。
  194.     if (base < 0) {
  195.         base = gpiochip_find_base(chip->ngpio);//这个函数在gpiolib.c中,在gpio_desc[]中分配chip->ngpio个空间(从最后往前分配),返回第一个index
  196.         if (base < 0) {
  197.             status = base;
  198.             goto unlock;
  199.         }
  200.         chip->base = base;
  201.     }

  202.     //确保这些分配的gpio号没有被其他chip占用
  203.     for (id = base; id < base + chip->ngpio; id++) {
  204.         if (gpio_desc[id].chip != NULL) {
  205.             status = -EBUSY;
  206.             break;
  207.         }
  208.     }
  209.     //填充gpio_desc,将该组内的每个GPIO口的gpio_desc结构和该组的控制结构chip联系起来
  210.     if (status == 0) {
  211.         for (id = base; id < base + chip->ngpio; id++) {
  212.             gpio_desc[id].chip = chip;
  213.             gpio_desc[id].flags = !chip->direction_input? (1 << FLAG_IS_OUT): 0;//设置GPIO口标志
  214.         }
  215.     }
  216.     of_gpiochip_add(chip);

  217. unlock:
  218.     spin_unlock_irqrestore(&gpio_lock, flags);

  219.     if (status)
  220.         goto fail;

  221.     status = gpiochip_export(chip);//与sysfs文件系统有关,这里不关心
  222.     if (status)
  223.         goto fail;

  224.     return 0;
  225. fail:
  226.     /* failures here can mean systems won't boot... */
  227.     pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",chip->base, chip->base + chip->ngpio - 1,chip->label ? : "generic");
  228.     return status;
  229. }

  230. 四.gpio的申请
  231. //所谓申请就是检测GPIO描述符desc->flags的FLAG_REQUESTED标志,已申请的话该标志是1,否则是0
  232. //往往多个gpio作为一个数组来进行申请
  233. int gpio_request_array(struct gpio *array, size_t num)
  234. {
  235.     int i, err;

  236.     for (i = 0; i < num; i++, array++) {//遍历数组中的每一个GPIO,gpio是GPIO号,flags是输入输出标志等,label是其取一个名字
  237.         err = gpio_request_one(array->gpio, array->flags, array->label);
  238.         if (err)
  239.             goto err_free;
  240.     }
  241.     return 0;

  242. err_free:
  243.     while (i--)
  244.         gpio_free((--array)->gpio);
  245.     return err;
  246. }

  247. int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
  248. {
  249.     int err;
  250.     
  251.     //gpio则为你要申请的哪一个管脚,label则是为其取一个名字。
  252.     err = gpio_request(gpio, label);
  253.     if (err)
  254.         return err;

  255.     if (flags & GPIOF_DIR_IN)//GPIO标志是输入
  256.         err = gpio_direction_input(gpio);//设置管脚为输入
  257.     else//GPIO标志是输出
  258.         err = gpio_direction_output(gpio,(flags & GPIOF_INIT_HIGH) ? 1 : 0);//根据标志确定输出1还是0

  259.     if (err)
  260.         gpio_free(gpio);

  261.     return err;
  262. }

  263. int gpio_request(unsigned gpio, const char *label)
  264. {
  265.     struct gpio_desc    *desc;
  266.     struct gpio_chip    *chip;
  267.     int            status = -EINVAL;
  268.     unsigned long        flags;
  269.     //屏蔽中断
  270.     spin_lock_irqsave(&gpio_lock, flags);

  271.     if (!gpio_is_valid(gpio))//判断是否有效,也就是参数的取值范围判断
  272.         goto done;
  273.         
  274.     //根据GPIO号找到对应的GPIO描述符结构
  275.     desc = &gpio_desc[gpio];
  276.     chip = desc->chip;//找到该GPIO所在的组控制器
  277.     if (chip == NULL)
  278.         goto done;
  279.         
  280.     //计数加1
  281.     if (!try_module_get(chip->owner))
  282.         goto done;

  283.     //这里测试并设置flags的第FLAG_REQUESTED位,如果没有被申请就返回该位的原值0
  284.     if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
  285.         desc_set_label(desc, label ? : "?");//设置GPIO描述符结构desc的label字段
  286.         status = 0;
  287.     } else {
  288.         status = -EBUSY;
  289.         module_put(chip->owner);
  290.         goto done;
  291.     }

  292.     if (chip->request) {/* chip->request may sleep */
  293.         spin_unlock_irqrestore(&gpio_lock, flags);
  294.         status = chip->request(chip, gpio - chip->base);
  295.         spin_lock_irqsave(&gpio_lock, flags);

  296.         if (status < 0) {
  297.             desc_set_label(desc, NULL);
  298.             module_put(chip->owner);
  299.             clear_bit(FLAG_REQUESTED, &desc->flags);
  300.         }
  301.     }

  302. done:
  303.     if (status)
  304.         pr_debug("gpio_request: gpio-%d (%s) status %d\n",gpio, label ? : "?", status);
  305.     spin_unlock_irqrestore(&gpio_lock, flags);
  306.     return status;
  307. }

  308. 五.GPIO的操作
  309. 1.设置GPIO为输出或输入
  310. int gpio_direction_input(unsigned gpio)
  311. {
  312.     unsigned long        flags;
  313.     struct gpio_chip    *chip;
  314.     struct gpio_desc    *desc = &gpio_desc[gpio];
  315.     int            status = -EINVAL;

  316.     spin_lock_irqsave(&gpio_lock, flags);
  317.     
  318.     //判断GPIO号是否有效
  319.     if (!gpio_is_valid(gpio))
  320.         goto fail;
  321.     //找到GPIO对应的gpio_chip结构
  322.     chip = desc->chip;
  323.     if (!chip || !chip->get || !chip->direction_input)
  324.         goto fail;
  325.     
  326.     //确保此GPIO是在此组内,chip->base是此组GPIO的起始号,chip->ngpio是此组GPIO的个数
  327.     gpio -= chip->base;
  328.     if (gpio >= chip->ngpio)
  329.         goto fail;
  330.         
  331.     //确保GPIO已申请
  332.     status = gpio_ensure_requested(desc, gpio);
  333.     if (status < 0)
  334.         goto fail;

  335.     //到这里可以确保GPIO是有效的
  336.     spin_unlock_irqrestore(&gpio_lock, flags);

  337.     might_sleep_if(chip->can_sleep);
  338.     //status=0
  339.     if (status) {
  340.         status = chip->request(chip, gpio);
  341.         if (status < 0) {
  342.             pr_debug("GPIO-%d: chip request fail, %d\n",chip->base + gpio, status);
  343.             goto lose;
  344.         }
  345.     }
  346.     //调用底层的已经设置过的操作,这里即davinci_direction_in
  347.     status = chip->direction_input(chip, gpio);
  348.     if (status == 0)//返回成功
  349.         clear_bit(FLAG_IS_OUT, &desc->flags);//清除输出标志
  350. lose:
  351.     return status;
  352. fail:
  353.     spin_unlock_irqrestore(&gpio_lock, flags);
  354.     if (status)
  355.         pr_debug("%s: gpio-%d status %d\n",__func__, gpio, status);
  356.     return status;
  357. }

  358. int gpio_direction_output(unsigned gpio, int value)
  359. {
  360.     //.........GPIO的检查,同上函数
  361.     
  362.     //调用底层的已经设置过的操作,这里即davinci_direction_out
  363.     status = chip->direction_output(chip, gpio, value);
  364.     if (status == 0)//返回成功
  365.         set_bit(FLAG_IS_OUT, &desc->flags);//设置输出标志
  366. lose:
  367.     return status;
  368. fail:
  369.     spin_unlock_irqrestore(&gpio_lock, flags);
  370.     if (status)
  371.         pr_debug("%s: gpio-%d status %d\n",__func__, gpio, status);
  372.     return status;
  373. }

  374. //根据前边对gpio_chip结构的初始化,会调用\arch\arm\mach-davinci\gpio.c里的函数
  375. static int davinci_direction_in(struct gpio_chip *chip, unsigned offset)
  376. {
  377.     return __davinci_direction(chip, offset, false, 0);
  378. }

  379. static int davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value)
  380. {
  381.     return __davinci_direction(chip, offset, true, value);
  382. }

  383. static inline int __davinci_direction(struct gpio_chip *chip,unsigned offset, bool out, int value)
  384. {
  385.     struct davinci_gpio_controller *d = chip2controller(chip);
  386.     struct davinci_gpio_regs __iomem *g = d->regs;//找到此组GPIO的控制寄存器地址
  387.     unsigned long flags;
  388.     u32 temp;
  389.     u32 mask = 1 << offset;

  390.     spin_lock_irqsave(&d->lock, flags);
  391.     temp = __raw_readl(&g->dir);//读出当前寄存器的输入输出方向
  392.     
  393.     if (out) {//为1设置输出
  394.         temp &= ~mask;
  395.         __raw_writel(mask, value ? &g->set_data : &g->clr_data);//确定是用于输出高电平还是输出低电平
  396.     } 
  397.     else {//为0设置为输入
  398.         temp |= mask;
  399.     }
  400.     __raw_writel(temp, &g->dir);//写入方向寄存器
  401.     spin_unlock_irqrestore(&d->lock, flags);

  402.     return 0;
  403. }

  404. 2.获取gpio的状态
  405. int __gpio_get_value(unsigned gpio)
  406. {
  407.     struct gpio_chip    *chip;

  408.     chip = gpio_to_chip(gpio);
  409.     WARN_ON(chip->can_sleep);
  410.     return chip->get ? chip->get(chip, gpio - chip->base) : 0;//调用davinci_gpio_get
  411. }

  412. static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset)
  413. {
  414.     struct davinci_gpio_controller *d = chip2controller(chip);
  415.     struct davinci_gpio_regs __iomem *g = d->regs;

  416.     return (1 << offset) & __raw_readl(&g->in_data);
  417. }

  418. 3.设置GPIO的值
  419. void __gpio_set_value(unsigned gpio, int value)
  420. {
  421.     struct gpio_chip    *chip;

  422.     chip = gpio_to_chip(gpio);
  423.     WARN_ON(chip->can_sleep);
  424.     chip->set(chip, gpio - chip->base, value);//调用davinci_gpio_set
  425. }

  426. static void davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
  427. {
  428.     struct davinci_gpio_controller *d = chip2controller(chip);
  429.     struct davinci_gpio_regs __iomem *g = d->regs;

  430.     __raw_writel((1 << offset), value ? &g->set_data : &g->clr_data);
  431. }

  432. 六、GPIO驱动编写
  433. 1.首先要申请GPIO口
  434. 2.注册设备
  435. 3.创建GPIO的sysfs相关文件
  436. #define GPIO_MAJOR 199         // major device NO.
  437. #define GPIO_MINOR 0         // minor device NO.
  438. #define DEVICE_NAME "omapl138_gpios" /*定义设备驱动的名字,或设备节点名称*/

  439. #define SET_OUTPUT_LOW 0
  440. #define SET_OUTPUT_HIGH 1
  441. #define GET_VALUE 2
  442. #define SET_INPUT 3

  443. static struct class *gpio_class;
  444. static struct gpio gpio_array[] =
  445. {
  446.     /*{ GPIO_TO_PIN(0, 0), GPIOF_OUT_INIT_LOW,     "RTU_WDI_SIGNAL" },will request fail*/
  447.     { GPIO_TO_PIN(0, 1), GPIOF_OUT_INIT_HIGH, "RTU_PLC_BAK_IO1"}, 
  448.     { GPIO_TO_PIN(0, 2), GPIOF_OUT_INIT_LOW,     "RTU_CHG_EN" }, 
  449.     { GPIO_TO_PIN(0, 3), GPIOF_IN,         "RTU_CHG_PG" }, 
  450.     { GPIO_TO_PIN(0, 5), GPIOF_IN,         "RTU_USB_OC_OUT" }, 
  451.     { GPIO_TO_PIN(0, 6), GPIOF_OUT_INIT_LOW,     "RTU_RUN_IND_LED" },
  452.     { GPIO_TO_PIN(1, 10), GPIOF_IN,         "RTU_TSC_BUSY"},
  453.     { GPIO_TO_PIN(1, 11), GPIOF_IN,        "RTU_PENIRQn" },
  454.     { GPIO_TO_PIN(1, 12), GPIOF_OUT_INIT_LOW, "RTU_uP_Q26x_RESET" }, 
  455.     { GPIO_TO_PIN(1, 13), GPIOF_OUT_INIT_HIGH, "RTU_uP_GPRS_PWR_EN" },
  456.     { GPIO_TO_PIN(1, 14), GPIOF_OUT_INIT_HIGH, "RTU_uP_Q26x_ON/OFF" }, 
  457.     { GPIO_TO_PIN(2, 1), GPIOF_OUT_INIT_LOW, "RTU_PLC_Reset" },
  458.     { GPIO_TO_PIN(2, 2), GPIOF_OUT_INIT_LOW, "RTU_PLC_T_Reg" }, 
  459.     { GPIO_TO_PIN(2, 4), GPIOF_OUT_INIT_LOW, "RTU_PLC_BAK_IO2" },
  460.     { GPIO_TO_PIN(2, 5), GPIOF_OUT_INIT_LOW, "RTU_RS485_RE" }, 
  461.     { GPIO_TO_PIN(2, 15), GPIOF_OUT_INIT_HIGH, "RTU_CHPWR_CS" },
  462.     { GPIO_TO_PIN(3, 9), GPIOF_OUT_INIT_HIGH, "RTU_RS485_DE" }, 
  463.     { GPIO_TO_PIN(6, 1), GPIOF_OUT_INIT_HIGH, "RTU_uP_VPIF_CLKO3" },
  464.     { GPIO_TO_PIN(6, 9), GPIOF_IN,         "RTU_KEY_IN2" },
  465.     { GPIO_TO_PIN(6, 11), GPIOF_IN,        "RTU_ALARM_IN5" },
  466.     { GPIO_TO_PIN(6, 15), GPIOF_OUT_INIT_HIGH,"RTU_uP_RESETOUTn" },
  467. };

  468. static int gpio_open(struct inode *inode,struct file *file)
  469. {
  470.     printk(KERN_WARNING"gpio open success!\n");
  471.     return 0;
  472. }

  473. static int gpio_release(struct inode *inode, struct file *filp)
  474. {
  475.   printk (KERN_ALERT "Device gpio released\n");
  476.   return 0;
  477. }

  478. static int gpio_read(struct file*f,char *dst,size_t size,loff_t*offset)
  479. {
  480.     unsigned char num;
  481.     __copy_to_user(&num,dst,1);
  482. #ifdef DEBUG
  483.      printk("__copy_to_user:%d\n",num);
  484. #endif

  485.     return 0;
  486. }

  487. static int gpio_write(struct file*f,const char *src,size_t size,loff_t *offset)
  488. {
  489.      unsigned char num;
  490.      __copy_from_user(&num,src,1);
  491. #ifdef DEBUG
  492.      printk("__copy_from_user:%d\n",num);
  493. #endif
  494.      return 0;

  495. }

  496. static long gpio_ioctl(struct file *file,unsigned int cmd,unsigned long gpio)
  497. {
  498.     int i;
  499.     unsigned long gpio_num = (gpio/100)*16+gpio%100;
  500.     for (i = 0; i < ARRAY_SIZE(gpio_array); i++) {
  501.         if(gpio_array[i].gpio == gpio_num)
  502.             goto valid_gpio;
  503.     }
  504.     return -1;
  505.         
  506. valid_gpio:
  507.     switch(cmd)//cmd表示应用程序传入的 GPIO 动作
  508.     {
  509.         case SET_OUTPUT_LOW://0
  510.         {
  511.             gpio_direction_output(gpio_num, 0);
  512.             break;
  513.         }
  514.         case SET_OUTPUT_HIGH://1
  515.         {
  516.             gpio_direction_output(gpio_num, 1);
  517.             break;
  518.         }
  519.         case GET_VALUE://2
  520.         {
  521.             return gpio_get_value(gpio_num);    
  522.         } 
  523.         case SET_INPUT://3
  524.         {
  525.             gpio_direction_input(gpio_num);
  526.             break;
  527.         }
  528.         default:
  529.         {
  530.             printk(KERN_EMERG "GPIO command mistake!!!\n");
  531.             break;
  532.         }
  533.     }
  534.     return 0;
  535. }
  536.         
  537. static const struct file_operations gpio_fops =
  538. {
  539.   .owner = THIS_MODULE,
  540.   .open = gpio_open,
  541.   .release = gpio_release,
  542.   .read = gpio_read,
  543.   .write = gpio_write,
  544.   .unlocked_ioctl = gpio_ioctl,
  545. };

  546. static int __init gpio_init(void) /*内核初始化会调用该函数*/
  547. {
  548.     int ret;
  549.     
  550.     ret = gpio_request_array(gpio_array, ARRAY_SIZE(gpio_array));
  551.     if (ret < 0) 
  552.     {
  553.         printk(KERN_EMERG "GPIO request failed\n");
  554.         goto request_failed; 
  555.     }
  556.     
  557.     dev_t my_dev_no;
  558.     struct cdev *gpio_cdev;
  559.     gpio_cdev = cdev_alloc();
  560.     if(gpio_cdev == NULL)
  561.     {
  562.         printk(KERN_EMERG "Cannot alloc cdev\n");
  563.         goto request_failed;
  564.     }
  565.     cdev_init(gpio_cdev,&gpio_fops);
  566.     gpio_cdev->owner=THIS_MODULE;
  567.     int result=alloc_chrdev_region(&my_dev_no,0,1,DEVICE_NAME); 
  568.     if(result < 0)
  569.     {
  570.         printk(KERN_EMERG "alloc_chrdev_region failed\n");
  571.         goto request_failed;
  572.     }
  573.     ret=cdev_add(gpio_cdev,my_dev_no,1); 
  574.     
  575.     
  576.   ret = register_chrdev(GPIO_MAJOR, DEVICE_NAME, &gpio_fops);//驱动字符设备
  577.      if(ret < 0)
  578.      {
  579.     printk(KERN_EMERG "GPIO register failed\n");
  580.     goto request_failed;
  581.      }
  582.     
  583.     //在sysfs文件系统下创建一个类
  584.   gpio_class = class_create(THIS_MODULE, DEVICE_NAME);
  585.   //device_create-->device_create_vargs-->device_register创建相应的sysfs文件(如dev文件),用于udev根据sysfs文件系统下的dev文件创建设备节点
  586.     device_create(gpio_class, NULL, MKDEV(GPIO_MAJOR, GPIO_MINOR), NULL, DEVICE_NAME);
  587.     return ret;
  588.     
  589. request_failed:
  590.     gpio_free_array(gpio_array, ARRAY_SIZE(gpio_array)); 
  591.     return ret;
  592. }

  593. static void __exit gpio_exit(void)
  594. {
  595.     device_destroy(gpio_class, MKDEV(GPIO_MAJOR, GPIO_MINOR));
  596.   class_unregister(gpio_class);
  597.   class_destroy(gpio_class);
  598.   unregister_chrdev(GPIO_MAJOR, DEVICE_NAME);
  599. }

  600. module_init(gpio_init);
  601. module_exit(gpio_exit);
  602. MODULE_LICENSE("GPL");
  603. MODULE_VERSION ("v2.0");
  604. MODULE_AUTHOR("wbl <>");
  605. MODULE_DESCRIPTION("OMAPL138 GPIO driver");
linux——驱动——GPIO子系统 GPIO(General Purpose Input/Output,通用输入输出)子系统是Linux内核中负责处理GPIO引脚的一个关键组件。它提供了一套接口,使得硬件工程师和软件开发者能够方便地使用和控制GPIO引脚,无论是初始化、设置引脚为输出并输出高低电平值,还是读取引脚的输入电平状态。的功能来与用户空间交互。例如控制LED、读取按键、触摸屏、鼠标都可以通过这些子系统接口实现。二、主要功能初始化GPIO:在系统启动时或设备驱动加载时,GPIO子系统负责初始化GPIO控制器及其下的引脚。 阅读详情

相关推荐

变频器相关使用

想用变频器传动带有改善功率因数用电容器的电机,电机却不动,原因是:变频器的电流流入改善功率因数用的电容器,由于其充电电流造成变频器过电流(OCT),所以不能起动,作为对策,请将电容器拆除后运转,甚至改善功率因数,在变频器的输入侧接入AC电抗器是有效的。一般电机利用装在轴上的外扇或转子端环上的叶片进行冷却,若速度降低则冷却效果下降,因而不能承受与高速运转相同的发热,必须降低在低速下的负载转矩,或采用容量大的变频器与电机组合,或采用专用电机。电流型是将电流源的直流变换为交流的变频器,其直流回路滤波石电感。

wangjie36的博客 3958

linux驱动开发学习笔记十六:gpio相关OF函数和子系统API函数

一、gpio相关OF函数 我们在设备节点中会定义了一个名为“gpios”的属性,当然不一定是“gpios”,你可以自定义。gpios 属性描述了 test 这个设备所使用的 GPIO。在驱动程序中需要读取 gpios 属性内容,Linux 内核提供了几个与 GPIO 有关的 OF 函数,常用的几个 OF 函数如下所示: of_gpio_named_count 函数 of_gpio_named_...

耐心的小黑的博客 5990

GPIO(简介、IO端口基本结构、GPIO的八种模式、GPIO寄存器、通用外设驱动模型、GPIO配置步骤、编程实战)

GPIO(简介、IO端口基本结构、GPIO的八种模式、GPIO寄存器、通用外设驱动模型、GPIO配置步骤、编程实战)

扬帆起航 3万+

使用gpio_direction_output()无法设置GPIO原因分析

3、通过逻辑分析仪抓到的波形分析可以看到,我们的driver是有一段时间把这个GPIO拉高的动作的,但是不久之后这个IO后就有一段很长的拉低拉高的波形,这个波形很像数据传输的波形,最后IO口被拉低,然后我们有理由怀疑这个IO口是和控制器冲突了,通过查看这个IO口可以知道GPIO3_D7在RK3399芯片中是I2S0控制器DATA0输出引脚。echo 1 > /sys/class/gpio/gpio127/value #设置GPIO3_D7输出高电平。linux 应用层操作GPIO。...

qq_27809619的博客 6196

TMS320F28377D的sys/bios双核工程配置详解——从零搭建到RAM优化

本文详细解析了TMS320F28377D双核系统在sys/bios环境下的工程配置与RAM优化策略。从开发环境搭建、SYS/BIOS工程创建到双核CMD文件配置,提供了实战技巧和常见问题解决方案,帮助开发者高效实现电力电子控制系统中的双核协作与性能优化。

weixin_28292761的博客 600

零、HarmonyOS应用开发者基础学习总览

零、HarmonyOS应用开发者基础学习总览

weixin_45029825的博客 1451

【正点原子STM32】GPIO(简介、IO端口基本结构、GPIO的八种模式、GPIO寄存器、通用外设驱动模型、GPIO配置步骤、编程实战)

GPIO的八种模式 输入浮空 F1系列 F4/F7/H7系列 作用:负责采集外部器件的信息或者控制外部器件工作,即输入输出 输入下拉 模拟功能 开漏输出 开漏式复用功能 输入上拉 推挽输出 推挽式复用功能 F4/F7/H7系列和F1系列的GPIO差异点 通用外设驱动模型(四步法) 1,初始化 时钟设置、参数设置、IO设置、中断设置(开中断、设NVIC)(可选) 2,读函数(可选) 从外设读取数据 3,写函数(可选) 往外设写入数据 4,中断服务函数(可选) 根据中断标志,处理外设各种中断事务

咖喱年糕的博客 9106

天池长期赛:二手车价格预测(422方案分享)

本次比赛是一次很好的锻炼数据挖掘能力的入门赛,从EDA-数据清洗-特征工程-模型调参-模型融合,能够完整的学习到大数据的分析和挖掘,值得历练。

weixin_46685991的博客 1万+

GPIO的驱动模型

原文地址:GPIO的驱动模型 作者:wangbaolin719 一、概述 GPIO是嵌入式系统最简单、最常用的资源了,比如点亮LED,控制蜂鸣器,输出高低电平,检测按键,等等。GPIO分输入和输出,在davinci linux中,有关GPIO的最底层的寄存器驱动,\arch\arm\mach-davinci目录下的gpio.c,这个是寄存器级的驱动,搞过单片机MCU的朋

u013690902的专栏 367

自动驾驶开发者必看:nuscenes数据集23类物体标注全解析(附避坑指南)

本文深入解析nuscenes数据集的23类物体标注系统,为自动驾驶开发者提供全面的标注规范解读和实战避坑指南。涵盖多模态数据组织、类别细分规则、属性系统应用技巧以及标注质量验证方法,帮助开发者高效利用这一标杆数据集提升模型性能。

weixin_29041767的博客 254

等保测评-瀚高数据库

一般适用于等保测评

m0_54146694的博客 1631

从裸机到Linux:GPIO驱动模型与libgpiod实战解析

在嵌入式系统开发中,GPIO(通用输入输出)是最基础且核心的硬件接口,它负责处理器与外部设备(如LED、按键、传感器)的直接交互。其工作原理是通过配置芯片引脚的电平状态(高/低)来实现数字信号的输入检测与输出控制,是嵌入式设备感知和控制物理世界的基石。GPIO的技术价值在于其通用性和灵活性,使得开发者能够通过软件编程灵活地定义硬件行为,从而连接和控制海量外部器件。在Linux操作系统环境下,GPIO的应用场景尤为广泛,从简单的LED闪烁、按键检测,到复杂的工业控制、物联网设备交互都离不开它。然而,与裸机开发

weixin_34245749的博客 306

【雷达通信】雷达信号处理仿真【含Matlab源码 2509期】

雷达信号处理仿真 完整的代码,方可运行;可提供运行操作视频!适合小白!

订阅付费专栏Matlab(奶茶价版),可赠送奶茶价版付费专栏指定代码1份; 903

通用外设驱动模型(四步法)及配置GPIO步骤

通用外设驱动模型四步法:初始化、读函数、写函数、中断服务函数。GPIO配置步骤及配置函数。

cykaw2590的博客 247

人工智能面试总结-分类与聚类

目录说说常用的分类算法,以及各自的优缺点?说说为什么正确率有时不能有效评估分类算法?说说什么样的分类器最好?说说聚类算法有哪些衡量标准?(选看)各聚类算法性能比较汇总说说什么是聚类,你知道哪些聚类算法?具体展开介绍你知道的聚类算法?说说K-Means聚类算法流程?说说K-Means聚类算法如何调优?说说K-Means聚类算法如何选择初始点?说说K-Means聚类聚的是特征还是样本?说说K-Means聚类的特征距离是如何计算的?说说聚类与分类的区别?手撕K-Means聚类 说说常用的分类算法,以及各自的优缺点

啥都生的博客 3860

RT-DETR改进策略【Conv和Transformer】| HiLo注意力机制 通过分离处理图像的高频和低频信息,高效处理图像特征

本文记录的是利用改进检测模型,针对目标检测中面临的多尺度特征融合效率与长距离依赖建模难题,HiLo注意力模块的引入旨在通过频率解耦策略优化高分辨率特征处理,将高频细节(如目标边缘)与低频语义(如场景结构)分离建模,提升目标检测精度。Fast Vision Transformers with HiLo AttentionHiLo注意力模块的提出源于对传统自注意力机制局限性的反思。传统多头自注意力(MSA)在处理高分辨率图像时存在以下问题:HiLo将注意力模块分为高频(Hi-Fi)和低频(Lo-Fi)两个分支,

Limiiiing的博客 814

Linux下GPIO驱动模型

转载地址:http://blog.sina.com.cn/s/blog_5ef638bc0100rzve.html GPIO是与硬件体系密切相关的,linux提供一个模型来让驱动统一处理GPIO,当然你也可以选择不用这个模型实现gpio。具体见说明文档Documention/gpio.txt。 下面粗略说一下这个模型关键的数据结构和函数:   为了给不同GPIO控制器提供一个

kunkliu的博客 2617

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Linux 下 GPIO驱动模型

转载地址:http://blog.chinaunix.net/uid-27717694-id-3624294.html一、概述GPIO是嵌入式系统最简单、最常用的资源了,比如点亮LED,控制蜂鸣器,输出高低电平,检测按键,等等。GPIO分输入和输出,在davinci linux中,有关GPIO的最底层的寄存器驱动,\arch\arm\mach-davinci目录下的gpio.c,这个是寄存器级的驱

Bruce.yang的嵌入式之旅 2506

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

GPIO的驱动模型——linux

一、概述 GPIO是嵌入式系统最简单、最常用的资源了,比如点亮LED,控制蜂鸣器,输出高低电平,检测按键,等等。GPIO分输入和输出,在davinci linux中,有关GPIO的最底层的寄存器驱动,\arch\arm\mach-davinci目录下的gpio.c,这个是寄存器级的驱动,搞过单片机MCU的朋友应该比较熟悉寄存器级的驱动。 GPIO的驱动主要就是读取GPIO口的状

bytxl的专栏 1800

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

linux 标准GPIO 驱动模型—version1

学习培训中

xuefeng_apple的专栏 2727
上一篇: Windows路径探究
下一篇: 常用git命令及注意事项
计算机与认知
博客等级 码龄14年 31粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值