39 解决全志h3 linux内核源码里的关于script.fex的bug

在script.fex里有关于io口的配置:

    Port:端口+组内序号<功能分配><内部电阻状态><驱动能力><输出电平状态>

    [gpio_para]
    gpio_used       = 1
    ;gpio_num        = 30
    ;gpio_pin_1      = port:PL10<1><default><default><1>
    ;gpio_pin_2      = port:PA15<1><default><default><0>
    ...

发现在内核源码里并没有对io口的上下拉功能,驱动电流等级等相关的配置寄存器进行设置,从而让io口的上下拉功能,驱动电流等功能根本无法应用.

自己写代码来根据script.bin里的io口相关设置来配置相应的寄存器解决这个问题:

1) 使用内核里的导出函数”script_get_pio_list”, 获取script.bin里关于主键”gpio_para”所有关于gpio的子键的配置值.

    script_item_u *list;
    n = script_get_pio_list("gpio_para", &list); //返回值为gpio口的个数

2) 映射关于io口的配置寄存器基地址, 并准备好每组的gpio口的配置寄存器.
这里写图片描述

根据上图,封装一个结构体。

#define PIO_BASE  0x01c20800
typedef volatile unsigned int uint32;
typedef struct {
    // gpio口的功能配置寄存器, 每个io口在配置寄存器里占用4位(实际用3位)
    uint32 CFGs[4];  //4个功能配置寄存器,每个寄存配置8个io口

    // gpio口的数据寄存器, 每个io口占用一位.
    uint32 DAT;

    // gpio口驱动电流配置寄存器, 每个io口占用2位 
    uint32 DRVs[2]; // 两个寄存器,每个寄存器配置16个io口

    // gpio口上下拉配置寄存器, 每个io口占用2位
    uint32 PULLs[2]; // 两个寄存器,每个寄存器配置16个io口

}PIO_t; //表示每组io口都有的配置寄存器

static PIO_t  *pios[7]; // 每个元素分别存放PA, PB, PC, PD, PE, PF, PG组io口的寄存器地址
static u8 *vaddr;

并在映射寄存器地址后,分配好每组io口的寄存器地址

    vaddr = ioremap(PIO_BASE, SZ_4K); //映射gpio配置寄存器的基地址
    if (NULL == vaddr)
        return -ENOMEM;

    for (i = 0; i < ARRAY_SIZE(pios); i++) //准备好每组io口的配置寄存器的地址
        pios[i] = (PIO_t *)(vaddr+i*0x24);

3) 再根据从script.bin获取出来的io口相关配置值来设置寄存器

    for (i = 0; i < n; i++)
    {
        //在内核里每组io口都算是32个一组,即使硬件上每组都没有32个io口那么多.
        //所以list[i].gpio.gpio / 32 即可算出是第几组, 
        j = list[i].gpio.gpio >> 5;   // pios[j]就是表示相应组的配置寄存结构体
        k = list[i].gpio.gpio & 31;  //算出在组内是第几个io口

        sel = list[i].gpio.mul_sel; //script.bin里io功能选择
        pull = list[i].gpio.pull;   //上下拉功能
        drv = list[i].gpio.drv_level; //驱动电流等级
        level = list[i].gpio.data;  //io口作输出时,输出什么电平


        if (-1 != sel) //功能选择不是<default>
        {
            pios[j]->CFGs[k>>3] &= ~(0xf << ((k&7)<<2));
            pios[j]->CFGs[k>>3] |= sel << ((k&7)<<2);

            if (1 == sel) //如果是输出,还需指定输出的电平
            {
                pios[j]->DAT &= ~(1<<k);
                pios[j]->DAT |= level << k;
            } 
        }
        if (-1 != pull) //上下拉功能不是<default>
        {
            pios[j]->PULLs[k>>4] &= ~(3 << ((k&15)<<1));
            pios[j]->PULLs[k>>4] |= pull << ((k&15)<<1);
        }   

        if (-1 != drv) //驱动电流等级不是<default>
        {
            pios[j]->DRVs[k>>4] &= ~(3 << ((k&15)<<1));
            pios[j]->DRVs[k>>4] |= drv << ((k&15)<<1);
        }
    }

完整代码:
h3gpio.c


#include <linux/init.h>
#include <linux/module.h>
#include <mach/sys_config.h>
#include <mach/pinctrl.h>
#include <asm/io.h>
#include <mach/gpio.h>

#define PIO_BASE  0x01c20800
typedef volatile unsigned int uint32;
typedef struct {
    // gpio口的功能配置寄存器, 每个io口在配置寄存器里占用4位(实际用3位)
    uint32 CFGs[4];  //4个功能配置寄存器,每个寄存配置8个io口

    // gpio口的数据寄存器, 每个io口占用一位.
    uint32 DAT;

    // gpio口驱动电流配置寄存器, 每个io口占用2位 
    uint32 DRVs[2]; // 两个寄存器,每个寄存器配置16个io口

    // gpio口上下拉配置寄存器, 每个io口占用2位
    uint32 PULLs[2]; // 两个寄存器,每个寄存器配置16个io口

}PIO_t; //表示每组io口都有的配置寄存器


static PIO_t  *pios[7]; // 每个元素分别存放PA, PB, PC, PD, PE, PF, PG组io口的寄存器地址
static u8 *vaddr;

static int __init h3gpio_init(void)
{
    script_item_u *list;
    int n, i, j, k;
    int sel, pull, drv, level;

    vaddr = ioremap(PIO_BASE, SZ_4K); //映射gpio配置寄存器的基地址
    if (NULL == vaddr)
        return -ENOMEM;

    for (i = 0; i < ARRAY_SIZE(pios); i++) //准备好每组io口的配置寄存器的地址
        pios[i] = (PIO_t *)(vaddr+i*0x24);

    // pa的配置寄存器0的地址 ==  &pios[0]->CFG0
    n = script_get_pio_list("gpio_para", &list); //返回值为gpio口的个数
    if (n <= 0)
        return -ENODEV;

    for (i = 0; i < n; i++)
    {
        //在内核里每组io口都算是32个一组,即使硬件上每组都没有32个io口那么多.
        //所以list[i].gpio.gpio / 32 即可算出是第几组, 
        j = list[i].gpio.gpio >> 5;   // pios[j]就是表示相应组的配置寄存结构体
        k = list[i].gpio.gpio & 31;  //算出在组内是第几个io口

        sel = list[i].gpio.mul_sel; //script.bin里io功能选择
        pull = list[i].gpio.pull;   //上下拉功能
        drv = list[i].gpio.drv_level; //驱动电流等级
        level = list[i].gpio.data;  //io口作输出时,输出什么电平

        if (-1 != sel) //功能选择不是<default>
        {
            pios[j]->CFGs[k>>3] &= ~(0xf << ((k&7)<<2));
            pios[j]->CFGs[k>>3] |= sel << ((k&7)<<2);

            if (1 == sel) //如果是输出,还需指定输出的电平
            {
                pios[j]->DAT &= ~(1<<k);
                pios[j]->DAT |= level << k;
            } 
        }
        if (-1 != pull) //上下拉功能不是<default>
        {
            pios[j]->PULLs[k>>4] &= ~(3 << ((k&15)<<1));
            pios[j]->PULLs[k>>4] |= pull << ((k&15)<<1);
        }   

        if (-1 != drv) //驱动电流等级不是<default>
        {
            pios[j]->DRVs[k>>4] &= ~(3 << ((k&15)<<1));
            pios[j]->DRVs[k>>4] |= drv << ((k&15)<<1);
        }
    }

    return 0;
}

static void __exit h3gpio_exit(void)
{
    iounmap(vaddr);
}


module_init(h3gpio_init);
module_exit(h3gpio_exit);

MODULE_LICENSE("GPL");
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值