字符設備驅動(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
 
         

 

 ### .... } ## }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM