gpio子系统之2440

来源:互联网 发布:淘宝搞笑收货人名字 编辑:程序博客网 时间:2024/06/06 05:30

先看板级定义的结构体

struct s3c_gpio_chip s3c24xx_gpios[] = {        [0] = {                .base   = S3C2410_GPACON,                .pm     = __gpio_pm(&s3c_gpio_pm_1bit),                .config = &s3c24xx_gpiocfg_banka,                .chip   = {                        .base                   = S3C2410_GPA(0),                        .owner                  = THIS_MODULE,                        .label                  = "GPIOA",                        .ngpio                  = 24,                        .direction_input        = s3c24xx_gpiolib_banka_input,                        .direction_output       = s3c24xx_gpiolib_banka_output,                },        },        [1] = {                .base   = S3C2410_GPBCON,                .pm     = __gpio_pm(&s3c_gpio_pm_2bit),                .chip   = {                        .base                   = S3C2410_GPB(0),                   //32                        .owner                  = THIS_MODULE,                        .label                  = "GPIOB",                        .ngpio                  = 16,                },        },。。。。。。。。。。。。。。        }, {                .base   = S3C2443_GPMCON,                .pm     = __gpio_pm(&s3c_gpio_pm_2bit),                .chip   = {                        .base                   = S3C2410_GPM(0),                        .owner                  = THIS_MODULE,                        .label                  = "GPIOM",                        .ngpio                  = 2,                },        },};

与平台相关的结构体s3c_gpio_chip,在板级配置端初始化了基地址和每个gpio控制器所管理的gpio数量等等。
在分析函数之前先来看一看S3C2410_GPA(0)
参考:http://blog.csdn.net/tang_jin_chan/article/details/12389069

.base           = S3C2410_GPA(0)  #define S3C2410_GPA(_nr)    (S3C2410_GPIO_A_START + (_nr))  enum s3c_gpio_number {      S3C2410_GPIO_A_START = 0,      S3C2410_GPIO_B_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_A),      S3C2410_GPIO_C_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_B),      S3C2410_GPIO_D_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_C),      S3C2410_GPIO_E_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_D),      S3C2410_GPIO_F_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_E),      S3C2410_GPIO_G_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_F),      S3C2410_GPIO_H_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_G),  };  #define S3C2410_GPIO_NEXT(__gpio) \      ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0)  #if CONFIG_S3C_GPIO_SPACE != 0  #error CONFIG_S3C_GPIO_SPACE cannot be zero at the moment  #endif   

这里的CONFIG_S3C_GPIO_SPAC是内核配置选项
CONFIG_S3C_GPIO_SPACE = 0

由此可以推知:
S3C2410_GPIO_A_START = 0
S3C2410_GPIO_B_START = S3C2410_GPIO_A_START + S3C2410_GPIO_A_NR + 0 + 0 = 0 + S3C2410_GPIO_A_NR + 0 + 0
其中,
、# define S3C2410_GPIO_A_NR (32)
所以,
S3C2410_GPIO_B_START = 0 + 32 + 0 + 0 = 32
因此,
对于gpio_chip_GPIOA:
.base = S3C2410_GPA(0) = S3C2410_GPIO_A_START + 0 = 0 + 0 = 0
对于gpio_chip_GPIOB:
.base = S3C2410_GPB(0) = S3C2410_GPIO_B_START + 0 = 32 + 0 = 32

这个.base在后面gpio_desc[id]数组填充时做参考。

下面分析具体函数。

static __init int s3c24xx_gpiolib_init(void){        struct s3c_gpio_chip *chip = s3c24xx_gpios;        int gpn;        for (gpn = 0; gpn < ARRAY_SIZE(s3c24xx_gpios); gpn++, chip++) {   //ARRAY_SIZE(s3c24xx_gpios)表示控制器的数量                if (!chip->config)                        chip->config = &s3c24xx_gpiocfg_default;  //做配置各个控制器上的gpio引脚使用                s3c_gpiolib_add(chip);               //注册        }        return 0;}

调用 s3c_gpiolib_add函数

int gpiochip_add(struct gpio_chip *chip){        unsigned long   flags;        int             status = 0;        unsigned        id;        int             base = chip->base;        if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))       //检验是否超过规定的引脚数量                        && base >= 0) {                status = -EINVAL;                goto fail;        }        spin_lock_irqsave(&gpio_lock, flags);        if (base < 0) {                base = gpiochip_find_base(chip->ngpio);           //动态分配空闲gpio引脚,并将最后找到的gpio号定为base                if (base < 0) {                        status = base;                        goto unlock;                }                chip->base = base;        }        /* these GPIO numbers must not be managed by another gpio_chip */        for (id = base; id < base + chip->ngpio; id++) {                               if (gpio_desc[id].chip != NULL) {                        //判断是否已经将chip赋值了                        status = -EBUSY;                        break;                }        }        if (status == 0) {                for (id = base; id < base + chip->ngpio; id++) {                        gpio_desc[id].chip = chip;                        //将chip赋值,每一组gpio口使用的chip一样。                        /* REVISIT:  most hardware initializes GPIOs as                         * inputs (often with pullups enabled) so power                         * usage is minimized.  Linux code should set the                         * gpio direction first thing; but until it does,                         * we may expose the wrong direction in sysfs.                         */                        gpio_desc[id].flags = !chip->direction_input                                ? (1 << FLAG_IS_OUT)                        //对flag赋值                                : 0;                }        }unlock:        spin_unlock_irqrestore(&gpio_lock, flags);        if (status == 0)                status = gpiochip_export(chip);                    //在/sys/class/下创建控制器gpiochip%d节点fail:        /* failures here can mean systems won't boot... */        if (status)                pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",                        chip->base, chip->base + chip->ngpio - 1,                        chip->label ? : "generic");        return status;}EXPORT_SYMBOL_GPL(gpiochip_add);
看看gpiochip_export这个函数static int gpiochip_export(struct gpio_chip *chip){        int             status;        struct device   *dev;        /* Many systems register gpio chips for SOC support very early,         * before driver model support is available.  In those cases we         * export this later, in gpiolib_sysfs_init() ... here we just         * verify that _some_ field of gpio_class got initialized.         */        if (!gpio_class.p)                return 0;        /* use chip->base for the ID; it's already known to be unique */        mutex_lock(&sysfs_lock);        dev = device_create(&gpio_class, chip->dev, MKDEV(0, 0), chip,                                "gpiochip%d", chip->base);                         //在/sys/class下创建gpiochip节点        if (!IS_ERR(dev)) {                status = sysfs_create_group(&dev->kobj,                        //在上面创建的节点下创建一些attr属性文件                                &gpiochip_attr_group);        } else                status = PTR_ERR(dev);        chip->exported = (status == 0);        mutex_unlock(&sysfs_lock);        if (status) {                unsigned long   flags;                unsigned        gpio;                spin_lock_irqsave(&gpio_lock, flags);                gpio = chip->base;                while (gpio_desc[gpio].chip == chip)                        gpio_desc[gpio++].chip = NULL;                spin_unlock_irqrestore(&gpio_lock, flags);                pr_debug("%s: chip %s status %d\n", __func__,                                chip->label, status);        }        return status;}int sysfs_create_group(struct kobject *kobj,                       const struct attribute_group *grp){        return internal_create_group(kobj, 0, grp);}static int internal_create_group(struct kobject *kobj, int update,                                 const struct attribute_group *grp){        struct sysfs_dirent *sd;        int error;        BUG_ON(!kobj || (!update && !kobj->sd));        /* Updates may happen before the object has been instantiated */        if (unlikely(update && !kobj->sd))                return -EINVAL;        if (grp->name) {                                     //没有名字 ,所以执行下面的                error = sysfs_create_subdir(kobj, grp->name, &sd);                if (error)                        return error;        } else                sd = kobj->sd;        sysfs_get(sd);                                              //原子量计数        error = create_files(sd, kobj, grp, update);                 //创建文件,里面把属性组的数据一个一个提取出来进行文件的创建。        if (error) {                if (grp->name)                        sysfs_remove_subdir(sd);        }        sysfs_put(sd);        return error;}

在应用层除了gpiochip0,还有export等文件,如果需要导出gpio端口到用户空间,可以直接 echo 19 > export
撤销GPIO的导出 ,可以 echo 19 > unexport
可是这两个文件是哪里来的呢?drivers/gpio/gpiolib.c文件下有如下定义。
static struct class_attribute gpio_class_attrs[] = { //属性定义
__ATTR(export, 0200, NULL, export_store),
__ATTR(unexport, 0200, NULL, unexport_store),
__ATTR_NULL,
};

static struct class gpio_class = {
.name = “gpio”,
.owner = THIS_MODULE,

    .class_attrs =  gpio_class_attrs,

};

在gpiolib_sysfs_init函数中有status = class_register(&gpio_class)–》 __class_register–》add_class_attrs

static int add_class_attrs(struct class *cls){        int i;        int error = 0;        if (cls->class_attrs) {                for (i = 0; attr_name(cls->class_attrs[i]); i++) {                        error = class_create_file(cls, &cls->class_attrs[i]);        //在类下创建文件节点                        if (error)                                goto error;                }        }done:        return error;error:        while (--i >= 0)                class_remove_file(cls, &cls->class_attrs[i]);        goto done;}

参考:http://blog.csdn.net/mirkerson/article/details/8464290
既然在/sys/class/gpio/下有了export节点,怎么用呢?
如echo 19 > export
19这个数字存放在下面函数的buf中。

static ssize_t export_store(struct class *class,                                struct class_attribute *attr,                                const char *buf, size_t len){        long    gpio;        int     status;        status = strict_strtol(buf, 0, &gpio);           //将buf中的数据格式转换后给gpio        if (status < 0)                goto done;        /* No extra locking here; FLAG_SYSFS just signifies that the         * request and export were done by on behalf of userspace, so         * they may be undone on its behalf too.         */        status = gpio_request(gpio, "sysfs");         //申请这个引脚        if (status < 0)                goto done;        status = gpio_export(gpio, true);               //下面看这个函数          if (status < 0)                gpio_free(gpio);        else                set_bit(FLAG_SYSFS, &gpio_desc[gpio].flags);done:        if (status)                pr_debug("%s: status %d\n", __func__, status);        return status ? : len;}int gpio_export(unsigned gpio, bool direction_may_change){        unsigned long           flags;        struct gpio_desc        *desc;        int                     status = -EINVAL;        const char              *ioname = NULL;        /* can't export until sysfs is available ... */        if (!gpio_class.p) {                pr_debug("%s: called too early!\n", __func__);                return -ENOENT;        }        if (!gpio_is_valid(gpio))                           // 判断是否有效,即在规定引脚范围里面                goto done;        mutex_lock(&sysfs_lock);        spin_lock_irqsave(&gpio_lock, flags);        desc = &gpio_desc[gpio];                                   //从数组中取出gpio描述符        if (test_bit(FLAG_REQUESTED, &desc->flags)                              // 判断是否已经被使用                        && !test_bit(FLAG_EXPORT, &desc->flags)) {                status = 0;                if (!desc->chip->direction_input                                || !desc->chip->direction_output)                        direction_may_change = false;        }        spin_unlock_irqrestore(&gpio_lock, flags);        if (desc->chip->names && desc->chip->names[gpio - desc->chip->base])                ioname = desc->chip->names[gpio - desc->chip->base];          //没有定义,不被调用        if (status == 0) {                struct device   *dev;                dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),           // 在类下创建设备gpio                                desc, ioname ? ioname : "gpio%u", gpio);                if (!IS_ERR(dev)) {                        status = sysfs_create_group(&dev->kobj,                         // 在设备gpio下创建属性文件                                                &gpio_attr_group);                        if (!status && direction_may_change)                                    status = device_create_file(dev,                           //  在设备gpio下创建属性文件                                                &dev_attr_direction);                        if (!status && gpio_to_irq(gpio) >= 0                                        && (direction_may_change                                                || !test_bit(FLAG_IS_OUT,                                                        &desc->flags)))                                status = device_create_file(dev,                       // 在设备gpio下创建属性文件                                                &dev_attr_edge);                        if (status != 0)                                device_unregister(dev);                } else                        status = PTR_ERR(dev);                if (status == 0)                        set_bit(FLAG_EXPORT, &desc->flags);        }        mutex_unlock(&sysfs_lock);done:        if (status)                pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);        return status;}EXPORT_SYMBOL_GPL(gpio_export);至此export所起的作用,已经解释完了,其他的类似。