B.Linux

灵魂构造师

导航

字符设备驱动(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\n", __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\n", __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

 


                    
        ###
        
        ....
    }
    ##
    
    
}

 

posted on 2019-06-26 21:44  B.Linux  阅读(3007)  评论(0编辑  收藏  举报