• 字符设备驱动(1)代码分析---之gpio_get_value


    在中断处理函数中,调用gpio_get_value/gpio_set_value()函数来获取/设置gpio端口的值,在这里简单分析一下内核的实现流程。

    tmp = gpio_get_value(S5PV210_GPH2(0));
    #define gpio_get_value    __gpio_get_value
    int __gpio_get_value(unsigned gpio)
    {
        struct gpio_chip    *chip;
        int value;
        chip = gpio_to_chip(gpio);
        
        
        ##
            {
             .base    = (S5P_VA_GPIO + 0xC40),
             .config    = &gpio_cfg_noint,
             .irq_base = IRQ_EINT(16),
                .chip    = {
                .base    = S5PV210_GPH2(0),
                .ngpio    = S5PV210_GPIO_H2_NR,
                .label    = "GPH2",
                .to_irq = samsung_gpiolib_to_irq,
            },
        ##
        
        
        value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
        //offset = gpio - chip->base
        trace_gpio_value(gpio, 1, value);
        return value;
        
        
        ##
    /****************************************************
        chip->get()函数的内核实现
    ****************************************************/
        //drivers/gpio/gpio-plat-samsung.c
        void __init samsung_gpiolib_add_4bit_chips
                (structs 3c_gpio_chip *chip,int nr_chips)
        {
            for (; nr_chips > 0; nr_chips--, chip++) {
                samsung_gpiolib_add_4bit(chip);
                s3c_gpiolib_add(chip);
            }
        }
    
        void __init samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
        {
            chip->chip.direction_input = samsung_gpiolib_4bit_input;
            chip->chip.direction_output = samsung_gpiolib_4bit_output;
            chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
        }
        
        //arch/arm/plat_samsung/gpio.c
        __init void s3c_gpiolib_add(struct s3c_gpio_chip *chip)
        {
            struct gpio_chip *gc = &chip->chip;    
            int ret;
            ....
            ....
            
            if (!gc->direction_input)
                gc->direction_input = s3c_gpiolib_input;
            if (!gc->direction_output)
                gc->direction_output = s3c_gpiolib_output;
            if (!gc->set)
                gc->set = s3c_gpiolib_set;
            
            if (!gc->get)
                gc->get = s3c_gpiolib_get;
            //至此完善后的结构体gc变为:
      gc = {
             .base    = (S5P_VA_GPIO + 0xC40),
             .config    = &gpio_cfg_noint,
             .irq_base = IRQ_EINT(16),
             .pm = __gpio_pm(&s3c_gpio_pm_4bit),
                .chip    = {
                .base    = S5PV210_GPH2(0),
                .ngpio    = S5PV210_GPIO_H2_NR,
                .label    = "GPH2",
                .to_irq = samsung_gpiolib_to_irq,
                .direction_input = samsung_gpiolib_4bit_input,
                .direction_output = samsung_gpiolib_4bit_output,
                .set = s3c_gpiolib_set,
                .get = s3c_gpiolib_get,
                },
    gc

             ###

    //samsung_gpiolib_4bit_input具体实现函数
     static int samsung_gpiolib_4bit_input(struct gpio_chip *chip,
                          unsigned int offset)
                {
                    struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
                    void __iomem *base = ourchip->base;
                    unsigned long con;
    
                    con = __raw_readl(base + GPIOCON_OFF);
                    con &= ~(0xf << con_4bit_shift(offset));
                    __raw_writel(con, base + GPIOCON_OFF);
    
                    gpio_dbg("%s: %p: CON now %08lx
    ", __func__, base, con);
    
                    return 0;
                }
    samsung_gpiolib_4bit_input
    static int samsung_gpiolib_4bit_output(struct gpio_chip *chip,
                                       unsigned int offset, int value)
                {
                    struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
                    void __iomem *base = ourchip->base;
                    unsigned long con;
                    unsigned long dat;
    
                    con = __raw_readl(base + GPIOCON_OFF);
                    con &= ~(0xf << con_4bit_shift(offset));
                    con |= 0x1 << con_4bit_shift(offset);
    
                    dat = __raw_readl(base + GPIODAT_OFF);
    
                    if (value)
                        dat |= 1 << offset;
                    else
                        dat &= ~(1 << offset);
                    //有点小疑问:为啥要写两次数据???
                    __raw_writel(dat, base + GPIODAT_OFF);
                    __raw_writel(con, base + GPIOCON_OFF);
                    __raw_writel(dat, base + GPIODAT_OFF);
    
                    gpio_dbg("%s: %p: CON %08lx, DAT %08lx
    ", __func__, base, con, dat);
    
                    return 0;
                }
    samsung_gpiolib_4bit_output
        //s3c_gpiolib_set、s3c_gpiolib_get的具体实现函数
    static void s3c_gpiolib_set(struct gpio_chip *chip,
                    unsigned offset, int value)
                {
                    struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
                    void __iomem *base = ourchip->base;
                    unsigned long flags;
                    unsigned long dat;
    
                    s3c_gpio_lock(ourchip, flags);
    
                    dat = __raw_readl(base + 0x04);
                    //将需要设定的位清零
                    dat &= ~(1 << offset);
                    //如果设定的值是1,则将相应位置1
                    if (value)
                        dat |= 1 << offset;
                    __raw_writel(dat, base + 0x04);
    
                    s3c_gpio_unlock(ourchip, flags);
                }
    s3c_gpiolib_set
    static int s3c_gpiolib_get(struct gpio_chip *chip, unsigned offset)
                {
                    struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
                    unsigned long val;
    
                    val = __raw_readl(ourchip->base + 0x04);
                    //将需要获取的位右移至最低位
                    val >>= offset;
                    //获取最低位的值并返回
                    val &= 1;
                    return val;
                }
    s3c_gpiolib_get
    
    
    
    
                        
            ###
            
            ....
        }
        ##
        
        
    }
  • 相关阅读:
    POJ2828
    Docker容器修改端口映射
    CentOS 7使用ISO镜像配置本地yum源
    Windows 自带的 Linux 子系统
    vue富文本编辑器插件vue-quill-editor使用
    修改docker容器存放位置
    Linux 硬盘相关操作
    centos7基础相关
    ubuntu-k8s搭建
    redhat 6.6 离线docker
  • 原文地址:https://www.cnblogs.com/embeded-linux/p/11094088.html
Copyright © 2020-2023  润新知