Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2691697
  • 博文数量: 505
  • 博客积分: 1552
  • 博客等级: 上尉
  • 技术积分: 2514
  • 用 户 组: 普通用户
  • 注册时间: 2007-09-23 18:24
文章分类

全部博文(505)

文章存档

2019年(12)

2018年(15)

2017年(1)

2016年(17)

2015年(14)

2014年(93)

2013年(233)

2012年(108)

2011年(1)

2009年(11)

分类: LINUX

2014-10-17 22:49:29

原文地址:linux GPIO驱动 作者:haoran9175

一、GPIO简介
GPIO即通用输入/输出接口,每个GPIO端口可通过软件分别配置成输入或输出。

CPU提供的GPIO接口一般都是多路复用的,CPU内部提供了对应的寄存器(配置寄存器、数据寄存器、上拉/下拉寄存器、
睡眠模式配置寄存器、睡眠模式拉/下拉寄存器),通过设置对应的寄存器的值,可配置GPIO口的功能。

二、LINUX内核中对GPIO的描述
1、gpio_desc结构
在driver/gpio/gpiolib.c中定义了gpio_desc结构,用于描述GPIO

点击(此处)折叠或打开

  1. struct gpio_desc {
  2.         struct gpio_chip    *chip;//描述GPIO控制器
  3.         unsigned long        flags;
  4.     /* 标志位符号数字*/
  5.     #define FLAG_REQUESTED    0
  6.     #define FLAG_IS_OUT    1
  7.     #define FLAG_RESERVED    2
  8.     #define FLAG_EXPORT    3    /* protected by sysfs_lock */
  9.     #define FLAG_SYSFS    4    /* exported via /sys/class/gpio/control */
  10.     #define FLAG_TRIG_FALL    5    /* trigger on falling edge */
  11.     #define FLAG_TRIG_RISE    6    /* trigger on rising edge */
  12.     #define FLAG_ACTIVE_LOW    7    /* sysfs value has active low */
  13.     
  14.     #define ID_SHIFT    16    /* add new flags before this one */
  15.     
  16.     #define GPIO_FLAGS_MASK        ((1 << ID_SHIFT) - 1)
  17.     #define GPIO_TRIGGER_MASK    (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
  18.     
  19.     #ifdef CONFIG_DEBUG_FS
  20.         const char        *label;
  21.     #endif
  22. };
  23. //gpio_desc用于保存所有的GPIO
  24. static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
2、gpio_chip结构
LINUX内核使用gpio_chip结构体描述GPIO控制器,定义在include/asm-generic/gpio.h中,

点击(此处)折叠或打开

  1. struct gpio_chip {
  2.     const char        *label;
  3.     struct device        *dev;
  4.     struct module        *owner;
  5.     int            (*request)(struct gpio_chip *chip,unsigned offset);//请求GPIO
  6.     void            (*free)(struct gpio_chip *chip,unsigned offset);//释放GPIO
  7.     int            (*direction_input)(struct gpio_chip *chip,unsigned offset);//配置GPIO为输入
  8.     int            (*get)(struct gpio_chip *chip,unsigned offset);//获得GPIO的值
  9.     int            (*direction_output)(struct gpio_chip *chip,unsigned offset, int value);//配置GPIO为输出
  10.     int            (*set_debounce)(struct gpio_chip *chip,unsigned offset, unsigned debounce);//设置去抖动的时间
  11.     void            (*set)(struct gpio_chip *chip,unsigned offset, int value);//设置GPIO的值
  12.     int            (*to_irq)(struct gpio_chip *chip,unsigned offset);//把GPIO转换为中断号
  13.     void            (*dbg_show)(struct seq_file *s,struct gpio_chip *chip);
  14.     int            base;//gpio控制器的gpio开始编号
  15.     u16            ngpio;//该控制器控制的GPIO数量
  16.     const char        *const *names;
  17.     unsigned        can_sleep:1;
  18.     unsigned        exported:1;

  19. #if defined(CONFIG_OF_GPIO)
  20.     /*
  21.      * If CONFIG_OF is enabled, then all GPIO controllers described in the
  22.      * device tree automatically may have an OF translation
  23.      */
  24.     struct device_node *of_node;
  25.     int of_gpio_n_cells;
  26.     int (*of_xlate)(struct gpio_chip *gc, struct device_node *np,
  27.          const void *gpio_spec, u32 *flags);
  28. #endif
  29. };
LINUX内核中定义了一些对gpio_chip操作的方法,声明在include/asm-generic/gpio.h中,如

点击(此处)折叠或打开

  1. //添加gpio_chip
  2. nt gpiochip_add(struct gpio_chip *chip);
  3. //删除gpio_chip
  4. int __must_check gpiochip_remove(struct gpio_chip *chip);
  5. int __must_check gpiochip_reserve(int start, int ngpio);
  6. struct gpio_chip *gpiochip_find(void *data,int (*match)(struct gpio_chip *chip,void *data));
3、各CPU体系在实现GPIO驱动时都对gpio_chip结构进行了封装,如s3c6410中,扩展了s3c_gpio_chip结构,
定义在arch/arm/plat-samsung/gpio-core.h中

点击(此处)折叠或打开

  1. struct s3c_gpio_chip {
  2.     struct gpio_chip    chip;//GPIO控制器
  3.     struct s3c_gpio_cfg    *config;//GPIO配置
  4.     struct s3c_gpio_pm    *pm;//电源管理信息
  5.     void __iomem        *base;//gpio配置寄存器基地址
  6.     int            irq_base;//中断号基址
  7.     int            group;
  8.     spinlock_t         lock;
  9. #ifdef CONFIG_PM
  10.     u32            pm_save[4];//挂起/恢复保存的信息
  11. #endif
  12. };

  13. //GPIO配置
  14. struct s3c_gpio_cfg {
  15.     unsigned int    cfg_eint;//外部中断
  16.     s3c_gpio_pull_t    (*get_pull)(struct s3c_gpio_chip *chip, unsigned offs);//读取当前上拉GPIO的配置
  17.     int        (*set_pull)(struct s3c_gpio_chip *chip, unsigned offs,s3c_gpio_pull_t pull);//设置当前上拉GPIO的配置
  18.     unsigned (*get_config)(struct s3c_gpio_chip *chip, unsigned offs);//读GPIO的当前配置
  19.     int     (*set_config)(struct s3c_gpio_chip *chip, unsigned offs,unsigned config);//设置GPIO的当前配置
  20. };

  21. //电源管理信息
  22. struct s3c_gpio_pm {
  23.     void (*save)(struct s3c_gpio_chip *chip);//常规保存gpio块的状态
  24.     void (*resume)(struct s3c_gpio_chip *chip);//恢复GPIO的块的状态
  25. };
三、S3C6410中对GPIO的实现
1、s3c_gpio_chip实例的定义
1)gpio_4bit定义,定义了GPA~GPM寄存器,每个GPIO口对应4bit

点击(此处)折叠或打开

  1. //arch/arm/mach-s3c64xx/gpiolib.c
  2. static struct s3c_gpio_chip gpio_4bit[] = {
  3.     {
  4.         .base    = S3C64XX_GPA_BASE,//gpio配置寄存器基地址
  5.         .config    = &gpio_4bit_cfg_eint0111,//GPIO配置
  6.         .chip    = {
  7.             .base    = S3C64XX_GPA(0),//gpio控制器的gpio开始编号
  8.             .ngpio    = S3C64XX_GPIO_A_NR,//该控制器控制的GPIO数量
  9.             .label    = "GPA",
  10.         },
  11.     }, {
  12.         .base    = S3C64XX_GPB_BASE,
  13.         .config    = &gpio_4bit_cfg_eint0111,
  14.         .chip    = {
  15.             .base    = S3C64XX_GPB(0),
  16.             .ngpio    = S3C64XX_GPIO_B_NR,
  17.             .label    = "GPB",
  18.         },
  19.     }, {
  20.         .base    = S3C64XX_GPC_BASE,
  21.         .config    = &gpio_4bit_cfg_eint0111,
  22.         .chip    = {
  23.             .base    = S3C64XX_GPC(0),
  24.             .ngpio    = S3C64XX_GPIO_C_NR,
  25.             .label    = "GPC",
  26.         },
  27.     }, {
  28.         .base    = S3C64XX_GPD_BASE,
  29.         .config    = &gpio_4bit_cfg_eint0111,
  30.         .chip    = {
  31.             .base    = S3C64XX_GPD(0),
  32.             .ngpio    = S3C64XX_GPIO_D_NR,
  33.             .label    = "GPD",
  34.         },
  35.     }, {
  36.         .base    = S3C64XX_GPE_BASE,
  37.         .config    = &gpio_4bit_cfg_noint,
  38.         .chip    = {
  39.             .base    = S3C64XX_GPE(0),
  40.             .ngpio    = S3C64XX_GPIO_E_NR,
  41.             .label    = "GPE",
  42.         },
  43.     }, {
  44.         .base    = S3C64XX_GPG_BASE,
  45.         .config    = &gpio_4bit_cfg_eint0111,
  46.         .chip    = {
  47.             .base    = S3C64XX_GPG(0),
  48.             .ngpio    = S3C64XX_GPIO_G_NR,
  49.             .label    = "GPG",
  50.         },
  51.     }, {
  52.         .base    = S3C64XX_GPM_BASE,
  53.         .config    = &gpio_4bit_cfg_eint0011,
  54.         .chip    = {
  55.             .base    = S3C64XX_GPM(0),
  56.             .ngpio    = S3C64XX_GPIO_M_NR,
  57.             .label    = "GPM",
  58.             .to_irq = s3c64xx_gpio2int_gpm,
  59.         },
  60.     },
  61. };
2)GPIO配置

点击(此处)折叠或打开

  1. static struct s3c_gpio_cfg gpio_4bit_cfg_noint = {
  2.     .set_config    = s3c_gpio_setcfg_s3c64xx_4bit,//设置GPIO的当前配置
  3.     .get_config    = s3c_gpio_getcfg_s3c64xx_4bit,//读GPIO的当前配置
  4.     .set_pull    = s3c_gpio_setpull_updown,//设置当前上拉GPIO的配置
  5.     .get_pull    = s3c_gpio_getpull_updown,//读取当前上拉GPIO的配置
  6. };

  7. static struct s3c_gpio_cfg gpio_4bit_cfg_eint0111 = {
  8.     .cfg_eint    = 7,
  9.     .set_config    = s3c_gpio_setcfg_s3c64xx_4bit,
  10.     .get_config    = s3c_gpio_getcfg_s3c64xx_4bit,
  11.     .set_pull    = s3c_gpio_setpull_updown,
  12.     .get_pull    = s3c_gpio_getpull_updown,
  13. };

  14. static struct s3c_gpio_cfg gpio_4bit_cfg_eint0011 = {
  15.     .cfg_eint    = 3,
  16.     .get_config    = s3c_gpio_getcfg_s3c64xx_4bit,
  17.     .set_config    = s3c_gpio_setcfg_s3c64xx_4bit,
  18.     .set_pull    = s3c_gpio_setpull_updown,
  19.     .get_pull    = s3c_gpio_getpull_updown,
  20. };
3)s3c_gpio_cfg对应的函数实现

点击(此处)折叠或打开

  1. //设置GPIO的当前配置
  2. int s3c_gpio_setcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip,
  3.                  unsigned int off, unsigned int cfg)
  4. {
  5.     void __iomem *reg = chip->base;//获取gpio配置寄存器基地址
  6.     unsigned int shift = (off & 7) * 4;
  7.     u32 con;

  8.     if (off < 8 && chip->chip.ngpio > 8)
  9.         reg -= 4;

  10.     if (s3c_gpio_is_cfg_special(cfg)) {
  11.         cfg &= 0xf;
  12.         cfg <<= shift;
  13.     }

  14.     con = __raw_readl(reg);
  15.     con &= ~(0xf << shift);//设置对应GPIO口的bit位为0
  16.     con |= cfg;
  17.     __raw_writel(con, reg);

  18.     return 0;
  19. }
  20. //读GPIO的当前配置
  21. unsigned s3c_gpio_getcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip,
  22.                  unsigned int off)
  23. {
  24.     void __iomem *reg = chip->base;//获取gpio配置寄存器基地址
  25.     unsigned int shift = (off & 7) * 4;
  26.     u32 con;

  27.     if (off < 8 && chip->chip.ngpio > 8)
  28.         reg -= 4;

  29.     con = __raw_readl(reg);//读取GPIO的值
  30.     con >>= shift;
  31.     con &= 0xf;

  32.     /* this conversion works for IN and OUT as well as special mode */
  33.     return S3C_GPIO_SPECIAL(con);
  34. }
  35. //设置当前上拉GPIO的配置
  36. int s3c_gpio_setpull_updown(struct s3c_gpio_chip *chip,
  37.              unsigned int off, s3c_gpio_pull_t pull)
  38. {
  39.     void __iomem *reg = chip->base + 0x08;//获取gpio配置寄存器基地址
  40.     int shift = off * 2;
  41.     u32 pup;

  42.     pup = __raw_readl(reg);
  43.     pup &= ~(3 << shift);
  44.     pup |= pull << shift;
  45.     __raw_writel(pup, reg);

  46.     return 0;
  47. }
  48. //读取当前上拉GPIO的配置
  49. s3c_gpio_pull_t s3c_gpio_getpull_updown(struct s3c_gpio_chip *chip,
  50.                     unsigned int off)
  51. {
  52.     void __iomem *reg = chip->base + 0x08;
  53.     int shift = off * 2;
  54.     u32 pup = __raw_readl(reg);

  55.     pup >>= shift;
  56.     pup &= 0x3;
  57.     return (__force s3c_gpio_pull_t)pup;
  58. }
4)gpio_4bit2定义,每个GPIO口对应4bit和2bit

点击(此处)折叠或打开

  1. static struct s3c_gpio_chip gpio_4bit2[] = {
  2.     {
  3.         .base    = S3C64XX_GPH_BASE + 0x4,
  4.         .config    = &gpio_4bit_cfg_eint0111,
  5.         .chip    = {
  6.             .base    = S3C64XX_GPH(0),
  7.             .ngpio    = S3C64XX_GPIO_H_NR,
  8.             .label    = "GPH",
  9.         },
  10.     }, {
  11.         .base    = S3C64XX_GPK_BASE + 0x4,
  12.         .config    = &gpio_4bit_cfg_noint,
  13.         .chip    = {
  14.             .base    = S3C64XX_GPK(0),
  15.             .ngpio    = S3C64XX_GPIO_K_NR,
  16.             .label    = "GPK",
  17.         },
  18.     }, {
  19.         .base    = S3C64XX_GPL_BASE + 0x4,
  20.         .config    = &gpio_4bit_cfg_eint0011,
  21.         .chip    = {
  22.             .base    = S3C64XX_GPL(0),
  23.             .ngpio    = S3C64XX_GPIO_L_NR,
  24.             .label    = "GPL",
  25.             .to_irq = s3c64xx_gpio2int_gpl,//把GPIO转换为中断号
  26.         },
  27.     },
  28. };
  29. //把GPIO转换为中断号
  30. int s3c64xx_gpio2int_gpl(struct gpio_chip *chip, unsigned pin)
  31. {
  32.     return pin >= 8 ? IRQ_EINT(16) + pin - 8 : -ENXIO;
  33. }
5)gpio_2bit定义,每个GPIO口对应2bit

点击(此处)折叠或打开

  1. static struct s3c_gpio_chip gpio_2bit[] = {
  2.     {
  3.         .base    = S3C64XX_GPF_BASE,
  4.         .config    = &gpio_2bit_cfg_eint11,
  5.         .chip    = {
  6.             .base    = S3C64XX_GPF(0),
  7.             .ngpio    = S3C64XX_GPIO_F_NR,
  8.             .label    = "GPF",
  9.         },
  10.     }, {
  11.         .base    = S3C64XX_GPI_BASE,
  12.         .config    = &gpio_2bit_cfg_noint,
  13.         .chip    = {
  14.             .base    = S3C64XX_GPI(0),
  15.             .ngpio    = S3C64XX_GPIO_I_NR,
  16.             .label    = "GPI",
  17.         },
  18.     }, {
  19.         .base    = S3C64XX_GPJ_BASE,
  20.         .config    = &gpio_2bit_cfg_noint,
  21.         .chip    = {
  22.             .base    = S3C64XX_GPJ(0),
  23.             .ngpio    = S3C64XX_GPIO_J_NR,
  24.             .label    = "GPJ",
  25.         },
  26.     }, {
  27.         .base    = S3C64XX_GPN_BASE,
  28.         .config    = &gpio_2bit_cfg_eint10,
  29.         .chip    = {
  30.             .base    = S3C64XX_GPN(0),
  31.             .ngpio    = S3C64XX_GPIO_N_NR,
  32.             .label    = "GPN",
  33.             .to_irq = s3c64xx_gpio2int_gpn,//把GPIO转换为中断号
  34.         },
  35.     }, {
  36.         .base    = S3C64XX_GPO_BASE,
  37.         .config    = &gpio_2bit_cfg_eint11,
  38.         .chip    = {
  39.             .base    = S3C64XX_GPO(0),
  40.             .ngpio    = S3C64XX_GPIO_O_NR,
  41.             .label    = "GPO",
  42.         },
  43.     }, {
  44.         .base    = S3C64XX_GPP_BASE,
  45.         .config    = &gpio_2bit_cfg_eint11,
  46.         .chip    = {
  47.             .base    = S3C64XX_GPP(0),
  48.             .ngpio    = S3C64XX_GPIO_P_NR,
  49.             .label    = "GPP",
  50.         },
  51.     }, {
  52.         .base    = S3C64XX_GPQ_BASE,
  53.         .config    = &gpio_2bit_cfg_eint11,
  54.         .chip    = {
  55.             .base    = S3C64XX_GPQ(0),
  56.             .ngpio    = S3C64XX_GPIO_Q_NR,
  57.             .label    = "GPQ",
  58.         },
  59.     },
  60. };
  61. //把GPIO转换为中断号
  62. int s3c64xx_gpio2int_gpn(struct gpio_chip *chip, unsigned pin)
  63. {
  64.     return IRQ_EINT(0) + pin;
  65. }
2、S3C6410中对GPIO初始化
在arch/arm/mach-s3c64xx/gpiolib.c中,调用三次s3c64xx_gpiolib_add()函数添加各GPIO

点击(此处)折叠或打开

  1. static __init int s3c64xx_gpiolib_init(void)
  2. {
  3.     s3c64xx_gpiolib_add(gpio_4bit, ARRAY_SIZE(gpio_4bit),
  4.              samsung_gpiolib_add_4bit);

  5.     s3c64xx_gpiolib_add(gpio_4bit2, ARRAY_SIZE(gpio_4bit2),
  6.              samsung_gpiolib_add_4bit2);

  7.     s3c64xx_gpiolib_add(gpio_2bit, ARRAY_SIZE(gpio_2bit),
  8.              s3c64xx_gpiolib_add_2bit);

  9.     return 0;
  10. }
  11. //用于声明内核初始化时调用
  12. core_initcall(s3c64xx_gpiolib_init);
1)s3c64xx_gpiolib_add定义

点击(此处)折叠或打开

  1. static __init void s3c64xx_gpiolib_add(struct s3c_gpio_chip *chips,
  2.                  int nr_chips,
  3.                  void (*fn)(struct s3c_gpio_chip *))
  4. {
  5.     //对各个s3c_gpio_chip调用fn和s3c_gpiolib_add函数
  6.     for (; nr_chips > 0; nr_chips--, chips++) {
  7.         if (fn)
  8.             (fn)(chips);
  9.         s3c_gpiolib_add(chips);
  10.     }
  11. }
2)samsung_gpiolib_add_4bit定义

点击(此处)折叠或打开

  1. void __init samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
  2. {
  3.     chip->chip.direction_input = samsung_gpiolib_4bit_input;////配置GPIO为输入
  4.     chip->chip.direction_output = samsung_gpiolib_4bit_output;////配置GPIO为输出
  5.     chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
  6. }
3)s3c_gpiolib_add定义

点击(此处)折叠或打开

  1. __init void s3c_gpiolib_add(struct s3c_gpio_chip *chip)
  2. {
  3.     struct gpio_chip *gc = &chip->chip;
  4.     int ret;

  5.     BUG_ON(!chip->base);
  6.     BUG_ON(!gc->label);
  7.     BUG_ON(!gc->ngpio);

  8.     spin_lock_init(&chip->lock);

  9.     if (!gc->direction_input)
  10.         gc->direction_input = s3c_gpiolib_input;
  11.     if (!gc->direction_output)
  12.         gc->direction_output = s3c_gpiolib_output;
  13.     if (!gc->set)
  14.         gc->set = s3c_gpiolib_set;
  15.     if (!gc->get)
  16.         gc->get = s3c_gpiolib_get;

  17. #ifdef CONFIG_PM
  18.     if (chip->pm != NULL) {
  19.         if (!chip->pm->save || !chip->pm->resume)
  20.             printk(KERN_ERR "gpio: %s has missing PM functions\n",
  21.              gc->label);
  22.     } else
  23.         printk(KERN_ERR "gpio: %s has no PM function\n", gc->label);
  24. #endif

  25.     //添加gpio_chip
  26.     ret = gpiochip_add(gc);
  27.     if (ret >= 0)
  28.         s3c_gpiolib_track(chip);
  29. }
四、gpiolib.c中提供的方法
1、gpiochip_add()方法

点击(此处)折叠或打开

  1. //注册一个gpio_chip
  2. int gpiochip_add(struct gpio_chip *chip)
  3. {
  4.     unsigned long    flags;
  5.     int        status = 0;
  6.     unsigned    id;
  7.     int        base = chip->base;//获得gpio控制器的gpio开始编号
  8.     //检测GPIO是否合法
  9.     if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))
  10.             && base >= 0) {
  11.         status = -EINVAL;
  12.         goto fail;
  13.     }
  14.     //定义自旋锁
  15.     spin_lock_irqsave(&gpio_lock, flags);

  16.     if (base < 0) {
  17.         //如果gpio控制器的gpio开始编号,重新获取gpio控制器的gpio开始编号
  18.         base = gpiochip_find_base(chip->ngpio);
  19.         if (base < 0) {
  20.             status = base;
  21.             goto unlock;
  22.         }
  23.         chip->base = base;
  24.     }

  25.     /* 检测gpio_chip是否重复 */
  26.     for (id = base; id < base + chip->ngpio; id++) {
  27.         if (gpio_desc[id].chip != NULL) {
  28.             status = -EBUSY;
  29.             break;
  30.         }
  31.     }
  32.     if (status == 0) {
  33.         for (id = base; id < base + chip->ngpio; id++) {
  34.             gpio_desc[id].chip = chip;

  35.             /* REVISIT: most hardware initializes GPIOs as
  36.              * inputs (often with pullups enabled) so power
  37.              * usage is minimized. Linux code should set the
  38.              * gpio direction first thing; but until it does,
  39.              * we may expose the wrong direction in sysfs.
  40.              */
  41.             gpio_desc[id].flags = !chip->direction_input
  42.                 ? (1 << FLAG_IS_OUT)
  43.                 : 0;
  44.         }
  45.     }

  46.     of_gpiochip_add(chip);

  47. unlock:
  48.     spin_unlock_irqrestore(&gpio_lock, flags);

  49.     if (status)
  50.         goto fail;

  51.     status = gpiochip_export(chip);
  52.     if (status)
  53.         goto fail;

  54.     return 0;
  55. fail:
  56.     /* failures here can mean systems won't boot... */
  57.     pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",
  58.         chip->base, chip->base + chip->ngpio - 1,
  59.         chip->label ? : "generic");
  60.     return status;
  61. }
2、gpiochip_remove()方法

点击(此处)折叠或打开

  1. //删除一个gpio_chip
  2. int gpiochip_remove(struct gpio_chip *chip)
  3. {
  4.     unsigned long    flags;
  5.     int        status = 0;
  6.     unsigned    id;

  7.     spin_lock_irqsave(&gpio_lock, flags);

  8.     of_gpiochip_remove(chip);

  9.     for (id = chip->base; id < chip->base + chip->ngpio; id++) {
  10.         if (test_bit(FLAG_REQUESTED, &gpio_desc[id].flags)) {
  11.             status = -EBUSY;
  12.             break;
  13.         }
  14.     }
  15.     if (status == 0) {
  16.         //设置gpio_desc中对应的gpio_chip指针为空
  17.         for (id = chip->base; id < chip->base + chip->ngpio; id++)
  18.             gpio_desc[id].chip = NULL;
  19.     }

  20.     spin_unlock_irqrestore(&gpio_lock, flags);

  21.     if (status == 0)
  22.         gpiochip_unexport(chip);

  23.     return status;
  24. }
3、gpio_request()方法

点击(此处)折叠或打开

  1. //请求gpio
  2. int gpio_request(unsigned gpio, const char *label)
  3. {
  4.     struct gpio_desc    *desc;
  5.     struct gpio_chip    *chip;
  6.     int            status = -EINVAL;
  7.     unsigned long        flags;

  8.     spin_lock_irqsave(&gpio_lock, flags);

  9.     if (!gpio_is_valid(gpio))//检测GPIO是否有效
  10.         goto done;
  11.     desc = &gpio_desc[gpio];//得到gpio对应的gpio_desc
  12.     chip = desc->chip;//得到gpio_chip
  13.     if (chip == NULL)
  14.         goto done;
  15.     //加载gpio对应对应的模块
  16.     if (!try_module_get(chip->owner))
  17.         goto done;

  18.     /* NOTE: gpio_request() can be called in early boot,
  19.      * before IRQs are enabled, for non-sleeping (SOC) GPIOs.
  20.      */

  21.     if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
  22.         desc_set_label(desc, label ? : "?");
  23.         status = 0;
  24.     } else {
  25.         status = -EBUSY;
  26.         module_put(chip->owner);
  27.         goto done;
  28.     }

  29.     if (chip->request) {
  30.         /* chip->request may sleep */
  31.         spin_unlock_irqrestore(&gpio_lock, flags);
  32.         //请求GPIO
  33.         status = chip->request(chip, gpio - chip->base);
  34.         spin_lock_irqsave(&gpio_lock, flags);

  35.         if (status < 0) {
  36.             desc_set_label(desc, NULL);
  37.             module_put(chip->owner);
  38.             clear_bit(FLAG_REQUESTED, &desc->flags);
  39.         }
  40.     }

  41. done:
  42.     if (status)
  43.         pr_debug("gpio_request: gpio-%d (%s) status %d\n",
  44.             gpio, label ? : "?", status);
  45.     spin_unlock_irqrestore(&gpio_lock, flags);
  46.     return status;
  47. }
4、gpio_free()方法

点击(此处)折叠或打开

  1. //释放GPIO
  2. void gpio_free(unsigned gpio)
  3. {
  4.     unsigned long        flags;
  5.     struct gpio_desc    *desc;
  6.     struct gpio_chip    *chip;

  7.     might_sleep();

  8.     if (!gpio_is_valid(gpio)) {
  9.         WARN_ON(extra_checks);
  10.         return;
  11.     }

  12.     gpio_unexport(gpio);

  13.     spin_lock_irqsave(&gpio_lock, flags);

  14.     desc = &gpio_desc[gpio];
  15.     chip = desc->chip;
  16.     if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) {
  17.         if (chip->free) {
  18.             spin_unlock_irqrestore(&gpio_lock, flags);
  19.             might_sleep_if(chip->can_sleep);
  20.             //释放GPIO
  21.             chip->free(chip, gpio - chip->base);
  22.             spin_lock_irqsave(&gpio_lock, flags);
  23.         }
  24.         desc_set_label(desc, NULL);
  25.         module_put(desc->chip->owner);
  26.         clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
  27.         clear_bit(FLAG_REQUESTED, &desc->flags);
  28.     } else
  29.         WARN_ON(extra_checks);

  30.     spin_unlock_irqrestore(&gpio_lock, flags);
  31. }
5、gpio_request_one()方法

点击(此处)折叠或打开

  1. //请求一个GPIO初始配置
  2. int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
  3. {
  4.     int err;
  5.     //申请一个gpio
  6.     err = gpio_request(gpio, label);
  7.     if (err)
  8.         return err;

  9.     //根据flags设置gpio为输入或输出
  10.     if (flags & GPIOF_DIR_IN)
  11.         err = gpio_direction_input(gpio);
  12.     else
  13.         err = gpio_direction_output(gpio,
  14.                 (flags & GPIOF_INIT_HIGH) ? 1 : 0);

  15.     if (err)
  16.         gpio_free(gpio);

  17.     return err;
  18. }
6、gpio_request_array()方法

点击(此处)折叠或打开

  1. //申请多个GPIO
  2. int gpio_request_array(const struct gpio *array, size_t num)
  3. {
  4.     int i, err;
  5.     //依次申请并设置GPIO
  6.     for (i = 0; i < num; i++, array++) {
  7.         err = gpio_request_one(array->gpio, array->flags, array->label);
  8.         if (err)
  9.             goto err_free;
  10.     }
  11.     return 0;

  12. err_free:
  13.     while (i--)
  14.         gpio_free((--array)->gpio);
  15.     return err;
  16. }
7、gpio_free_array()方法

点击(此处)折叠或打开

  1. //释放多个GPIO
  2. void gpio_free_array(const struct gpio *array, size_t num)
  3. {
  4.     while (num--)
  5.         gpio_free((array++)->gpio);
  6. }
8、gpio_direction_input()方法

点击(此处)折叠或打开

  1. //设置GPIO为输入
  2. int gpio_direction_input(unsigned gpio)
  3. {
  4.     unsigned long        flags;
  5.     struct gpio_chip    *chip;
  6.     struct gpio_desc    *desc = &gpio_desc[gpio];
  7.     int            status = -EINVAL;

  8.     spin_lock_irqsave(&gpio_lock, flags);

  9.     if (!gpio_is_valid(gpio))//检测GPIO是否有效
  10.         goto fail;
  11.     chip = desc->chip;
  12.     if (!chip || !chip->get || !chip->direction_input)
  13.         goto fail;
  14.     gpio -= chip->base;
  15.     if (gpio >= chip->ngpio)
  16.         goto fail;
  17.     status = gpio_ensure_requested(desc, gpio);//确保GPIO已申请
  18.     if (status < 0)
  19.         goto fail;

  20.     /* now we know the gpio is valid and chip won't vanish */

  21.     spin_unlock_irqrestore(&gpio_lock, flags);

  22.     might_sleep_if(chip->can_sleep);

  23.     if (status) {
  24.         status = chip->request(chip, gpio);
  25.         if (status < 0) {
  26.             pr_debug("GPIO-%d: chip request fail, %d\n",
  27.                 chip->base + gpio, status);
  28.             /* and it's not available to anyone else ...
  29.              * gpio_request() is the fully clean solution.
  30.              */
  31.             goto lose;
  32.         }
  33.     }
  34.     //设置GPIO为输入
  35.     status = chip->direction_input(chip, gpio);
  36.     if (status == 0)
  37.         clear_bit(FLAG_IS_OUT, &desc->flags);

  38.     trace_gpio_direction(chip->base + gpio, 1, status);
  39. lose:
  40.     return status;
  41. fail:
  42.     spin_unlock_irqrestore(&gpio_lock, flags);
  43.     if (status)
  44.         pr_debug("%s: gpio-%d status %d\n",
  45.             __func__, gpio, status);
  46.     return status;
  47. }
9、gpio_direction_output()方法

点击(此处)折叠或打开

  1. //设置GPIO为输出
  2. int gpio_direction_output(unsigned gpio, int value)
  3. {
  4.     unsigned long        flags;
  5.     struct gpio_chip    *chip;
  6.     struct gpio_desc    *desc = &gpio_desc[gpio];
  7.     int            status = -EINVAL;

  8.     spin_lock_irqsave(&gpio_lock, flags);

  9.     if (!gpio_is_valid(gpio))//检测GPIO是否有效
  10.         goto fail;
  11.     chip = desc->chip;
  12.     if (!chip || !chip->set || !chip->direction_output)
  13.         goto fail;
  14.     gpio -= chip->base;
  15.     if (gpio >= chip->ngpio)
  16.         goto fail;
  17.     status = gpio_ensure_requested(desc, gpio);//确保GPIO已申请
  18.     if (status < 0)
  19.         goto fail;


  20.     /* now we know the gpio is valid and chip won't vanish */

  21.     spin_unlock_irqrestore(&gpio_lock, flags);

  22.     might_sleep_if(chip->can_sleep);

  23.     if (status) {
  24.         status = chip->request(chip, gpio);
  25.         if (status < 0) {
  26.             pr_debug("GPIO-%d: chip request fail, %d\n",
  27.                 chip->base + gpio, status);
  28.             /* and it's not available to anyone else ...
  29.              * gpio_request() is the fully clean solution.
  30.              */
  31.             goto lose;
  32.         }
  33.     }
  34.     //设置GPIO为输出
  35.     status = chip->direction_output(chip, gpio, value);
  36.     if (status == 0)
  37.         set_bit(FLAG_IS_OUT, &desc->flags);
  38.     trace_gpio_value(chip->base + gpio, 0, value);
  39.     trace_gpio_direction(chip->base + gpio, 0, status);
  40. lose:
  41.     return status;
  42. fail:
  43.     spin_unlock_irqrestore(&gpio_lock, flags);
  44.     if (status)
  45.         pr_debug("%s: gpio-%d status %d\n",
  46.             __func__, gpio, status);
  47.     return status;
  48. }
10、__gpio_get_value()方法

点击(此处)折叠或打开

  1. //获取GPIO的值
  2. int __gpio_get_value(unsigned gpio)
  3. {
  4.     struct gpio_chip    *chip;
  5.     int value;

  6.     chip = gpio_to_chip(gpio);
  7.     WARN_ON(chip->can_sleep);
  8.     //获取GPIO的值
  9.     value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
  10.     trace_gpio_value(gpio, 1, value);
  11.     return value;
  12. }
11、__gpio_set_value()方法

点击(此处)折叠或打开

  1. //设置GPIO的值
  2. void __gpio_set_value(unsigned gpio, int value)
  3. {
  4.     struct gpio_chip    *chip;

  5.     chip = gpio_to_chip(gpio);
  6.     WARN_ON(chip->can_sleep);
  7.     trace_gpio_value(gpio, 0, value);
  8.     chip->set(chip, gpio - chip->base, value);
  9. }
五、GPIO驱动模板

点击(此处)折叠或打开

  1. #define GPIO_MAJOR 230         // major device NO.
  2. #define GPIO_MINOR 0         // minor device NO.
  3. #define DEVICE_NAME "gpios"

  4. #define SET_OUTPUT_LOW 0
  5. #define SET_OUTPUT_HIGH 1
  6. #define GET_VALUE 2
  7. #define SET_INPUT 3

  8. static struct class *gpio_class;
  9. static struct gpio gpio_array[] =
  10. {
  11.     { GPIO_TO_PIN(0, 0), GPIOF_OUT_INIT_LOW,     "RTU_WDI_SIGNAL" },
  12.     { GPIO_TO_PIN(0, 1), GPIOF_OUT_INIT_HIGH, "RTU_PLC_BAK_IO1"},
  13. };

  14. static int gpio_open(struct inode *inode,struct file *file)
  15. {
  16.     printk(KERN_WARNING"gpio open success!\n");
  17.     return 0;
  18. }

  19. static int gpio_release(struct inode *inode, struct file *filp)
  20. {
  21.   printk (KERN_ALERT "Device gpio released\n");
  22.   return 0;
  23. }

  24. static long gpio_ioctl(struct file *file,unsigned int cmd,unsigned long gpio)
  25. {
  26.     int i;
  27.     unsigned long gpio_num = (gpio/100)*16+gpio%100;
  28.     for (i = 0; i < ARRAY_SIZE(gpio_array); i++) {
  29.         if(gpio_array[i].gpio == gpio_num)
  30.             goto valid_gpio;
  31.     }
  32.     return -1;
  33.         
  34. valid_gpio:
  35.     switch(cmd)//cmd表示应用程序传入的 GPIO 动作
  36.     {
  37.         case SET_OUTPUT_LOW://0
  38.         {
  39.             gpio_direction_output(gpio_num, 0);
  40.             break;
  41.         }
  42.         case SET_OUTPUT_HIGH://1
  43.         {
  44.             gpio_direction_output(gpio_num, 1);
  45.             break;
  46.         }
  47.         case GET_VALUE://2
  48.         {
  49.             return gpio_get_value(gpio_num);    
  50.         }
  51.         case SET_INPUT://3
  52.         {
  53.             gpio_direction_input(gpio_num);
  54.             break;
  55.         }
  56.         default:
  57.         {
  58.             printk(KERN_EMERG "GPIO command mistake!!!\n");
  59.             break;
  60.         }
  61.     }
  62.     return 0;
  63. }
  64.         
  65. static const struct file_operations gpio_fops =
  66. {
  67.   .owner = THIS_MODULE,
  68.   .open = gpio_open,
  69.   .release = gpio_release,
  70.   .unlocked_ioctl = gpio_ioctl,
  71. };


  72. //驱动加载函数
  73. static int __init gpio_init(void)
  74. {
  75.     int ret;
  76.     //注册一些列GPIO
  77.     ret = gpio_request_array(gpio_array, ARRAY_SIZE(gpio_array));
  78.     if (ret < 0)
  79.     {
  80.         printk(KERN_EMERG "GPIO request failed\n");
  81.         goto request_failed;
  82.     }
  83.     
  84.     const char *name = DEVICE_NAME;
  85.     dev_t my_dev_no;
  86.     struct cdev *gpio_cdev;
  87.     //分配cdev结构体
  88.     gpio_cdev = cdev_alloc();
  89.     if(gpio_cdev == NULL)
  90.     {
  91.         printk(KERN_EMERG "Cannot alloc cdev\n");
  92.         goto request_failed;
  93.     }
  94.     //初始化cdev结构体
  95.     cdev_init(gpio_cdev,&gpio_fops);
  96.     gpio_cdev->owner=THIS_MODULE;
  97.     int result=alloc_chrdev_region(&my_dev_no,0,1,DEVICE_NAME); //动态分配设备号
  98.     if(result < 0)
  99.     {
  100.         printk(KERN_EMERG "alloc_chrdev_region failed\n");
  101.         goto request_failed;
  102.     }
  103.     kobject_set_name(&cdev->kobj, "%s", name);
  104.     ret=cdev_add(gpio_cdev,my_dev_no,1);     
  105.      if(ret < 0)
  106.      {
  107.     printk(KERN_EMERG "GPIO register failed\n");
  108.     goto request_failed;
  109.      }
  110.     
  111.     //在sysfs文件系统下创建一个类
  112.   gpio_class = class_create(THIS_MODULE, DEVICE_NAME);
  113.   ///dev中创建设备节点
  114.     device_create(gpio_class, NULL, my_dev_no, NULL, DEVICE_NAME);
  115.     return ret;
  116.     
  117. request_failed:
  118.     gpio_free_array(gpio_array, ARRAY_SIZE(gpio_array));
  119.     return ret;
  120. }

  121. static void __exit gpio_exit(void)
  122. {
  123.     device_destroy(gpio_class, MKDEV(GPIO_MAJOR, GPIO_MINOR));
  124.   class_unregister(gpio_class);
  125.   unregister_chrdev(GPIO_MAJOR, DEVICE_NAME);
  126. }

  127. module_init(gpio_init);
  128. module_exit(gpio_exit);
  129. MODULE_LICENSE("GPL");















阅读(1695) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~